package kz.arta.synergy.workflow.mobile.android.forms.mobile.manager;

import android.os.AsyncTask;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import kz.arta.synergy.workflow.mobile.android.common.models.Person;
import kz.arta.synergy.workflow.mobile.android.common.requests.RestClient;
import kz.arta.synergy.workflow.mobile.android.common.requests.SendGetRequest;
import kz.arta.synergy.workflow.mobile.android.common.utils.MyApplication;
import kz.arta.synergy.workflow.mobile.android.common.utils.Wrapper;
import kz.arta.synergy.workflow.mobile.android.forms.mobile.FormConstants;
import kz.arta.synergy.workflow.mobile.android.forms.mobile.models.FormData;
import kz.arta.synergy.workflow.mobile.android.forms.mobile.models.FormDescription;
import kz.arta.synergy.workflow.mobile.android.forms.mobile.models.FormDictionary;

/**
 * Created by neox on 30.06.15.
 * Класс используется для формирования описания формы (json), который получит мобильный просмоторщик форм
 */
public class MobileFormJson extends AsyncTask<Void, Void, String> {

    /**
     * Идентификатор формы
     */
    private String formUUID;

    /**
     * UUID данных по форме
     */
    private String dataUUID;

    /**
     * Пользователь
     */
    private Person person;

    /**
     * Клсс для работы с запросами на сервер
     */
    private SendGetRequest sendGetRequest;

    /**
     * Описание формы
     */
    private FormDescription formDescription;

    /**
     * Данные по форме
     */
    private FormData formData;

    /**
     * Справочники, которые используются в форме (KEY - идентификатор справочника, VALUE - его значение)
     */
    private Map<String, String> dictMap = new HashMap<>();

    public MobileFormJson(String formUUID, String dataUUID, Person person) {
        this.formUUID = formUUID;
        this.dataUUID = dataUUID;
        this.person = person;
        sendGetRequest = new SendGetRequest(person);
    }

    @Override
    protected String doInBackground(Void... params) {
        // получение описание формы
        String form = sendGetRequest.requestGET(person.getHost() + "rest/api/asforms/form/" +
                formUUID + "?locale=" + MyApplication.getLang() + "&isMobile=true");
        if (form == null) {
            return Wrapper.wrapError("Ошибка получения описания формы");
        }
        if (form.equals("{}")) {
            return Wrapper.wrapError("Форма не имеет мобильного представления");
        }
        // получение описания формы
        try {
            formDescription = RestClient.getGson().fromJson(form, FormDescription.class);
        } catch (Exception exc) {
            return Wrapper.wrapError("Ошибка получения описания формы");
        }
        if (formUUID != null) {
            getFormData();
        }
        return getMobileJson();
    }

    /**
     * Метод получает данные по форме
     */
    private void getFormData() {
        // получение описания данных по форме (если есть)
        String data = sendGetRequest.requestGET(person.getHost() + "rest/api/asforms/data/" +
                dataUUID + "?locale=" + MyApplication.getLang());
        formData = RestClient.getGson().fromJson(data, FormData.class);
    }

    /**
     * Метод выполняет преобразование json строки из той, что вернул сервер в ту, которую будет распознавать мобильный просмоторщик форм
     *
     * @return json строка, которую будет распонавать мобильный просмоторщик форм
     */
    private String getMobileJson() {
        // если вдруг описание формы не получено - говорим, что произошла ошибка
        if (formDescription == null) {
            return Wrapper.wrapError("Ошибка получения описания формы");
        }
        // результат выполнения метода
        StringBuilder result = new StringBuilder("[");
        // инициализация справочников
        initDictionary();
        // преобразование каждого компонента в объект json
        for (FormDescription.Properties item : formDescription.properties) {
            switch (item.type) {
                case FormConstants.LABEL:
                    result.append(getLabel(item)).append(",");
                    break;
                case FormConstants.TEXT_BOX:
                    result.append(getTextBox(item)).append(",");
                    break;
                case FormConstants.TEXT_AREA:
                    result.append(getTextArea(item)).append(",");
                    break;
                case FormConstants.LIST_BOX:
                    result.append(getListBox(item)).append(",");
                    break;
            }
        }
        if (result.length() > 1) {
            result.delete(result.length() - 1, result.length());
        }
        result.append("]");
        return result.toString();
    }

    /**
     * Инциализация справочников
     */
    private void initDictionary() {
        // получение справочников, которые используются в форме
        for (FormDescription.DataSources item : formDescription.datasources) {
            if (item.type.equals(FormConstants.DICT)) {
                dictMap.put(item.dict, getDictionary(item.dict));
            }
        }
    }

    /**
     * Метод возвращает описание компонента как строку json (Неизменяемый текст)
     *
     * @param item описание компонента
     * @return описание компонента в виде json строки
     */
    private String getLabel(FormDescription.Properties item) {
        StringBuilder builder = new StringBuilder("{");
        builder.append(Wrapper.getItem("id", item.id)).append(",");
        if (item.config != null && item.config.read_only) {
            builder.append(Wrapper.getItem("enabled", "false")).append(",");
        } else {
            builder.append(Wrapper.getItem("enabled", "true")).append(",");
        }
        builder.append(Wrapper.getItem("required", String.valueOf(item.required))).append(",");
        builder.append(Wrapper.getItem("label", (item.label != null ? item.label : ""))).append(",");
        builder.append(Wrapper.getItem("type", item.type));
        builder.append("}");
        return builder.toString();
    }

    /**
     * Метод возвращает описание компонента как строку json (Однострочное поле)
     *
     * @param item описание компонента
     * @return описание компонента в виде json строки
     */
    private String getTextBox(FormDescription.Properties item) {
        StringBuilder builder = new StringBuilder("{");
        builder.append(Wrapper.getItem("id", item.id)).append(",");
        if (item.config != null && item.config.read_only) {
            builder.append(Wrapper.getItem("enabled", "false")).append(",");
        } else {
            builder.append(Wrapper.getItem("enabled", "true")).append(",");
        }
        builder.append(Wrapper.getItem("required", String.valueOf(item.required))).append(",");
        builder.append(Wrapper.getItem("label", (item.label != null ? item.label : ""))).append(",");
        builder.append(Wrapper.getItem("type", item.type)).append(",");
        builder.append(Wrapper.getItem("value", getDefaultValue(item.id)));
        builder.append("}");
        return builder.toString();
    }

    /**
     * Метод возвращает описание компонента как строку json (Многострочное поле)
     *
     * @param item описание компонента
     * @return описание компонента в виде json строки
     */
    private String getTextArea(FormDescription.Properties item) {
        StringBuilder builder = new StringBuilder("{");
        builder.append(Wrapper.getItem("id", item.id)).append(",");
        if (item.config != null && item.config.read_only) {
            builder.append(Wrapper.getItem("enabled", "false")).append(",");
        } else {
            builder.append(Wrapper.getItem("enabled", "true")).append(",");
        }
        builder.append(Wrapper.getItem("required", String.valueOf(item.required))).append(",");
        builder.append(Wrapper.getItem("label", (item.label != null ? item.label : ""))).append(",");
        builder.append(Wrapper.getItem("type", item.type)).append(",");
        builder.append(Wrapper.getItem("value", getDefaultValue(item.id)));
        builder.append("}");
        return builder.toString();
    }

    /**
     * Метод возвращает описание компонента как строку json (Выпадающий список)
     *
     * @param item описание компонента
     * @return описание компонента в виде json строки
     */
    private String getListBox(FormDescription.Properties item) {
        StringBuilder builder = new StringBuilder("{");
        builder.append(Wrapper.getItem("id", item.id)).append(",");
        if (item.config != null && item.config.read_only) {
            builder.append(Wrapper.getItem("enabled", "false")).append(",");
        } else {
            builder.append(Wrapper.getItem("enabled", "true")).append(",");
        }
        builder.append(Wrapper.getItem("required", String.valueOf(item.required))).append(",");
        builder.append(Wrapper.getItem("label", (item.label != null ? item.label : ""))).append(",");
        builder.append(Wrapper.getItem("type", item.type)).append(",");
        builder.append(Wrapper.getItem("value", getDefaultValue(item.id))).append(",");
        builder.append("\"data\":").append(getDataListBox(item.id));
        builder.append("}");
        return builder.toString();
    }

    /**
     * Метод возвращает значение для компонентов TextBox/TextArea/ListBox (либо значение по умолчанию, либо значение из данных по форме)
     *
     * @param id идентификатор компонента
     * @return значение по умолчанию
     */
    private String getDefaultValue(String id) {
        // если есть данные по форме
        if (dataUUID == null || formData.data.length == 0) {
            for (FormDescription.Data item : formDescription.data) {
                if (item.id.equals(id)) {
                    return item.def;
                }
            }
        } else {
            for (FormData.DataUUID item : formData.data) {
                if (item.id.equals(id)) {
                    return item.value;
                }
            }
        }
        return "";
    }

    /**
     * Метод возвращает даные для выпадающего списка
     *
     * @param id идентификатор компонента
     * @return json строка (key/value)
     */
    private String getDataListBox(String id) {
        StringBuilder result = new StringBuilder("[");
        // получение данных для компонента из данных
        for (FormDescription.Data item : formDescription.data) {
            if (item.id.equals(id) && item.values != null) {
                for (FormDescription.Values values : item.values) {
                    result.append("{");
                    result.append(Wrapper.getItem("value", values.value)).append(",");
                    result.append(Wrapper.getItem("label", values.label));
                    result.append("},");
                }
            }
        }
        // получение данных для компонента из справочников
        for (FormDescription.DataSources item : formDescription.datasources) {
            if (item.id.equals(id)) {
                // описание словария как json
                String jsonDict = dictMap.get(item.dict);
                if (jsonDict == null) {
                    return "[]";
                }
                // десериализация словаря
                FormDictionary formDictionary = RestClient.getGson().fromJson(jsonDict, FormDictionary.class);
                if (formDictionary == null) {
                    return "[]";
                }
                // uuid нужной колонки (значение)
                String valueColumnID = null;
                // uuid нужной колонки (ключ)
                String keyColumnID = null;
                // поиск нужных колонок
                for (FormDictionary.Columns columns : formDictionary.columns) {
                    if (item.value.equals(columns.code)) {
                        valueColumnID = columns.columnID;
                    }
                    if (item.key.equals(columns.code)) {
                        keyColumnID = columns.columnID;
                    }
                }
                // поиск нужных значений
                List<String> values = new ArrayList<>();
                List<String> labels = new ArrayList<>();
                for (FormDictionary.Items dictionaryItem : formDictionary.items) {
                    for (FormDictionary.Values dictionaryValue : dictionaryItem.values) {
                        if (dictionaryValue.columnID.equals(valueColumnID)) {
                            values.add(dictionaryValue.value);
                        }
                        if (dictionaryValue.columnID.equals(keyColumnID)) {
                            labels.add(dictionaryValue.value);
                        }
                    }
                }
                // получение строки
                for (int i = 0; i < values.size(); i++) {
                    result.append("{");
                    result.append(Wrapper.getItem("value", values.get(i))).append(",");
                    result.append(Wrapper.getItem("label", labels.get(i)));
                    result.append("},");
                }
            }
        }
        if (result.length() > 1) {
            result.delete(result.length() - 1, result.length());
        }
        result.append("]");
        return result.toString();
    }

    /**
     * Метод возвращает описание справочника на основе инденитфикатора
     *
     * @param key идентификатор справочника
     * @return json
     */
    private String getDictionary(String key) {
        try {
            return sendGetRequest.requestGET(person.getHost() +
                    "rest/api/dictionary/get_by_code?dictionaryCode=" + URLEncoder.encode(key, "utf-8"));
        } catch (Exception exc) {
            return "";
        }
    }
}
