/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Release
* (c) Copyright IBM Corporation 2011, 2017. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*/
package com.urbancode.air.plugin.jira;

import java.util.ArrayList;
import java.util.List;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import com.urbancode.commons.webext.util.JSONUtilities;

public class JiraChange {

    //**********************************************************************************************
    // CLASS
    //**********************************************************************************************

    //**********************************************************************************************
    // INSTANCE
    //**********************************************************************************************
    final private String name;
    final private String description;
    final private String id;
    final private String key;
    final private String typeId;
    final private String typeName;
    final private String statusId;
    final private String statusName;
    final private String priorityId;
    final private String priorityName;
    private String initiativeId;
    private String initiativeName;
    final private List<JiraRelease> releases = new ArrayList<JiraRelease>();
    final private List<JiraComponent> components = new ArrayList<JiraComponent>();
    private List<String> parentLinkKeys = new ArrayList<String>();
    private List<String> childLinkKeys = new ArrayList<String>();
    // Only used for custom field mapping of Application
    private HashMap<String,String> projectNames = new HashMap<String,String>();

    final static private APPLICATION = "Application"
    final static private COMPONENT   = "Components"
    final static private INITIATIVE  = "Initiative"
    final static private RELEASE     = "Release"
    final static private INITIATIVE_NAME = "InitiativeName"

    //----------------------------------------------------------------------------------------------
    public JiraChange(JSONObject json, HashMap<String, String> customFields) throws JSONException {
        JSONObject fields = JSONUtilities.getJsonObjectFromJsonObject(json, "fields");

        name = (JSONUtilities.getStringFromJsonObject(fields, "summary")?:"").trim();
        if (name.length() > 253) {
            name = name.substring(0, 250) + "..."
        }

        description = JSONUtilities.getStringFromJsonObject(fields, "description");
        id = JSONUtilities.getStringFromJsonObject(json, "id");
        key = JSONUtilities.getStringFromJsonObject(json, "key");
        typeId = JSONUtilities.getStringFromJsonObject(
                JSONUtilities.getJsonObjectFromJsonObject(fields, "issuetype"), "id");
        typeName = (JSONUtilities.getStringFromJsonObject(
                JSONUtilities.getJsonObjectFromJsonObject(fields, "issuetype"), "name")?:"").trim();
        statusId = JSONUtilities.getStringFromJsonObject(
                JSONUtilities.getJsonObjectFromJsonObject(fields, "status"), "id");
        statusName = (JSONUtilities.getStringFromJsonObject(
                JSONUtilities.getJsonObjectFromJsonObject(fields, "status"), "name")?:"").trim();
        try {
            priorityId = JSONUtilities.getStringFromJsonObject(
                    JSONUtilities.getJsonObjectFromJsonObject(fields, "priority"), "id");
            priorityName = (JSONUtilities.getStringFromJsonObject(
                JSONUtilities.getJsonObjectFromJsonObject(fields, "priority"), "name")?:"").trim();
        } catch (NullPointerException ex) {
            // Swallow NullPointerException
            // Likely only on JIRA v7
        }

        // Reecord all Components assigned to this issue
        setCustomValueInit(fields, COMPONENT, "components")

        // CUSTOM APPLICATION FIELD
        if (customFields.containsKey(APPLICATION)) {
            setCustomValueInit(fields, APPLICATION, customFields.get(APPLICATION))
        }

        // CUSTOM RELEASE FIELD
        // Else Manual Mapping is Used
        if (customFields.containsKey(RELEASE)) {
            setCustomValueInit(fields, RELEASE, customFields.get(RELEASE))
        }

        // CUSTOM INITIATIVE FIELD
        if (customFields.containsKey(INITIATIVE)) {
            setCustomValueInit(fields, INITIATIVE, customFields.get(INITIATIVE))
        }

        // CUSTOM INITIATIVE FIELD
        if (customFields.containsKey(INITIATIVE_NAME)) {
            setCustomValueInit(fields, INITIATIVE_NAME, customFields.get(INITIATIVE_NAME))
        }

        //Get Parent Links
        JSONArray links = JSONUtilities.getJsonArrayFromJsonObject(fields, "issuelinks");

        if (links) {
            for(int i=0; i < links.length(); i++) {
                JSONObject link = links.getJSONObject(i)

                if(link.has("inwardIssue")) {
                    this.parentLinkKeys.add(link.getJSONObject("inwardIssue").getString("key"))
                }
                if(link.has("outwardIssue")) {
                    this.childLinkKeys.add(link.getJSONObject("outwardIssue").getString("key"))
                }
            }
        }
    }

    //----------------------------------------------------------------------------------------------
    public String getName() {
        return name;
    }

    //----------------------------------------------------------------------------------------------
    public String getDescription() {
        return description;
    }

    //----------------------------------------------------------------------------------------------
    public String getId() {
        return id;
    }

    //----------------------------------------------------------------------------------------------
    public String getKey() {
        return key;
    }

    //----------------------------------------------------------------------------------------------
    public String getTypeId() {
        return typeId;
    }

    //----------------------------------------------------------------------------------------------
    public String getTypeName() {
        return typeName;
    }

    //----------------------------------------------------------------------------------------------
    public String getStatusId() {
        return statusId;
    }

    //----------------------------------------------------------------------------------------------
    public String getStatusName() {
        return statusName;
    }

    //----------------------------------------------------------------------------------------------
    public String getPriorityId() {
        return priorityId;
    }

    //----------------------------------------------------------------------------------------------
    public String getPriorityName() {
        return priorityName;
    }

    //----------------------------------------------------------------------------------------------
    public String getInitiativeName() {
        return initiativeName;
    }

    //----------------------------------------------------------------------------------------------
    public String getInitiativeId() {
        return initiativeId;
    }

    //----------------------------------------------------------------------------------------------
    public List<JiraRelease> getReleases() {
        return releases;
    }

    //----------------------------------------------------------------------------------------------
    public List<JiraComponent> getComponents() {
        return components;
    }

    //----------------------------------------------------------------------------------------------
    public List<String> getParentLinks() {
        return parentLinkKeys;
    }

    //----------------------------------------------------------------------------------------------
    public List<String> getChildLinks() {
        return childLinkKeys;
    }

    //----------------------------------------------------------------------------------------------
    public HashMap<String,String> getProjectNames() {
        return projectNames;
    }

    //----------------------------------------------------------------------------------------------
    /**
     * param fields JSONObject containing JIRA Issue Data
     * param customFields HashMap of customField ID and mapped uRelease field
     * @returns Custom Field Release ID and Name are Set
     */
    private void setCustomValueInit(JSONObject fields, String customFieldType, String customFieldId) {
        def customFieldValue = JSONUtilities.getStringFromJsonObject(fields, customFieldId)
        // If Custom Field is null, ignore
        if (customFieldValue) {
            // Multiple Releases in JSONArray
            if (customFieldValue.startsWith("[")) {
                setCustomValue(customFieldType, JSONUtilities.getJsonArrayFromJsonObject(fields, customFieldId))
            }
            // Single Release in JSON
            else if (customFieldValue.startsWith("{")) {
                setCustomValue(customFieldType, JSONUtilities.getJsonObjectFromJsonObject(fields, customFieldId))
            }
            // Single Release in String
            else {
                setCustomValue(customFieldType, customFieldValue)
            }
        }
    }

    //----------------------------------------------------------------------------------------------
    private void setCustomValue(String customFieldType, JSONArray jsonArray) {
        for (int i = 0; i < jsonArray.length(); i++) {
            setCustomValue(customFieldType, jsonArray.getJSONObject(i))
        }
    }

    //----------------------------------------------------------------------------------------------
    private void setCustomValue(String customFieldType, JSONObject jsonObj) {
        def name = JSONUtilities.getStringFromJsonObject(jsonObj, "name")
        // If "name" property doesn't exist, set name as "value" instead
        if (!name) {
            name = JSONUtilities.getStringFromJsonObject(jsonObj, "value")
        }
        def id = JSONUtilities.getStringFromJsonObject(jsonObj, "id")
        setCustomValue(customFieldType, name + ":" + id)
    }

    //----------------------------------------------------------------------------------------------
    private void setCustomValue(String customFieldType, String jsonStr) {
        // Delimit the String by a _ or :
        int colonIndex = jsonStr.lastIndexOf(":")
        int underscoreIndex = jsonStr.lastIndexOf("_")
        int i = colonIndex > underscoreIndex ? colonIndex : underscoreIndex

        // Construct name and id strings, default to jsonStr
        String name = jsonStr
        String id = jsonStr
        if (i > -1) {
            name = jsonStr.substring(0,i).trim()
            id = jsonStr.substring(i+1).trim()
        }

        if(customFieldType == APPLICATION) {
            this.projectNames.put(id, name)
        }
        else if(customFieldType == INITIATIVE) {
            this.initiativeName = name
            this.initiativeId = id
        }
        else if(customFieldType == INITIATIVE_NAME) {
            this.initiativeName = name
        }
        else if (customFieldType == RELEASE) {
            JSONObject obj = new JSONObject()
            obj.put("name", name)
            obj.put("id", id)
            releases.add(new JiraRelease(obj))
        }
        else if (customFieldType == COMPONENT) {
            JSONObject obj = new JSONObject()
            obj.put("name", name)
            obj.put("id", id)
            components.add(new JiraComponent(obj))
        }
        else {
            throw new Exception("[Error] Unknown ${customFieldType}' customFieldType reached in setCustomValue.")
        }
    }
}
