/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.queplix.qwoss.client.frames.mainframe;

import com.queplix.core.client.app.rpc.RPC;
import com.queplix.core.client.app.vo.EntityData;
import com.queplix.core.client.app.vo.EntityReferenceData;
import com.queplix.core.client.app.vo.EntityReferenceDataRequest;
import com.queplix.core.client.app.vo.FamgMeta;
import com.queplix.core.client.app.vo.FieldData;
import com.queplix.core.client.app.vo.FieldDataRequest;
import com.queplix.core.client.app.vo.FieldMeta;
import com.queplix.core.client.app.vo.GridData;
import com.queplix.core.client.app.vo.GridSearchProperties;
import com.queplix.core.client.app.vo.ListboxDataRequest;
import com.queplix.core.client.app.vo.ListboxFieldData;
import com.queplix.core.client.app.vo.MemoFieldData;
import com.queplix.core.client.app.vo.InFormGridFieldData;
import com.queplix.core.client.app.vo.RowData;
import com.queplix.core.client.app.vo.SubsetData;
import com.queplix.core.client.app.vo.TextareaFieldData;
import com.queplix.core.client.app.vo.TextboxFieldData;
import com.queplix.core.client.common.CollectionsHelper;
import com.queplix.core.client.common.StringUtil;
import com.queplix.core.client.common.ui.DialogHelper;
import com.queplix.core.client.frames.email.EmailComposeHelper;
import com.queplix.core.client.frames.htmledit.HtmlEditFrame;
import com.queplix.core.client.frames.mainframe.FormOperations;
import com.queplix.core.client.frames.mainframe.FormState;
import com.queplix.core.client.frames.mainframe.OperationTypes;
import com.queplix.qwoss.client.app.rpc.CustomRPC;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

/**
 * Description:
 *
 * @author rustem.nizamiev, sergei.savchuk
 */
public class TicketHandler extends OSSOperationStrategy {

    protected static final String TICKET_ID_CAPTION = "Ticket : ";

    private static final long BASE_ENTITYROWID = -1;
    private static final int SELECTED_INDEX = 0;
    private static final int STATUS_OWNED = 2;

    private static final String CHANGE_OWNER_QUESTION = "Would you like to change the owner?";

    // ticket form menu options    
    private static final String MY_QUEUES = "myQueues";
    private static final String MY_TICKETS = "myTickets";
    private static final String OPEN_TICKETS = "openTickets";
    private static final String ACCEPT_TICKET = "acceptTicket";
    // ticket form custom buttons
    private static final String LINK_TO_INTERACTION_BUTTON  = "LINK_TO_INTERACTION_BUTTON";
    private static final String NEW_SOLUTION_BUTTON = "NEW_SOLUTION_BUTTON";
    private static final String SEND_EMAIL_BUTTON = "SEND_EMAIL_BUTTON";
    private static final String ATTACH_FILE_BUTTON = "ATTACH_FILE";
    // tickets fields
    protected static final String TICKET_ID_FIELD_NAME = "qw_ticketid";
    protected static final String SUBJECT_FIELD_NAME = "qw_problem";
    protected static final String DESCRIPTION_FIELD_NAME = "qw_description";
    protected static final String DESCRIPTION_TEXT_FIELD_NAME = "qw_descriptiontext";
    protected static final String RESPONSE_FIELD_NAME = "qw_response";
    protected static final String RESPONSE_TEXT_FIELD_NAME = "qw_responsetext";
    protected static final String OWNER_FIELD_NAME = "qw_ownerid";
    protected static final String AGENT_FIELD_NAME = "qw_agentid";
    protected static final String STATUS_FIELD_NAME = "qw_status";
    protected static final String COMPONENT_ID_FIELD_NAME = "qw_componentid"; // 1st constrained control
    protected static final String REP_BVERSION_ID_FIELD_NAME = "qw_repbuildversionid"; // 2nd constrained control
    protected static final String RES_BVERSION_ID_FIELD_NAME = "qw_resbuildversionid"; // 3rd constrained control
    protected static final String REP_ENV_ID_FIELD_NAME = "qw_repenvironmentid"; // 4th constrained control
    protected static final String TEST_ENV_ID_FIELD_NAME = "qw_testenvironmentid"; // 5th constrained control
    protected static final String PRODUCT_ID_FIELD_NAME = "qw_productid"; // constraint-source control
    protected static final String CUSTOMER_ID_FIELD_NAME = "qw_customerid";
    protected static final String EMPLOYEE_ID_FIELD_NAME = "qw_employeeid";
    protected static final String CUR_INTERACTION_ID_FIELD = "qw_cur_interaction";
    protected static final String SUB_CATEGORY_FIELD_NAME  = "qw_subcategory"; //filtering field
    protected static final String CATEGORY_FIELD_NAME  = "qw_category"; //filter sub-category by category id
    
    // fields from external forms
    // solution:
    protected static final String SOLUTION_CUR_TICKET_ID_FIELD = "qw_cur_ticket";
    private static final String SOLUTION_PRODUCT_FIELD = "qw_productid";
    private static final String SOLUTION_COMPONENT_FIELD = "qw_componentid";
    protected static final String SOLUTION_SUMMARY_FIELD = "qw_summary";
    protected static final String SOLUTION_PROBLEM_FIELD = "qw_problem";
    protected static final String SOLUTION_PROBLEM_TEXT_FIELD = "qw_problemtext";
    protected static final String SOLUTION_SOL_FIELD = "qw_solution";
    protected static final String SOLUTION_SOL_TEXT_FIELD = "qw_solutiontext";
    // interaction:
    private static final String LINKED_TICKETS_FIELD = "linked_tickets"; // hidden IFG on Interaction form
    private static final String INTERACTION_ID_FIELD = "qw_interactionid";

    // external entities and fields used in handler logic 
    private static final String CUSTOMER_TICKET_ENTITY_NAME = "customer.foreign";
    private static final String CUSTOMER_TICKET_ENTITY_PKEYFIELD_NAME = "qw_customerid";
    // field name in entity, where this entityReference is referencing.
    static final String COMPONENT_FILTER_FIELD_NAME = "qw_productid";
    private static final String BVERSION_FILTER_FIELD_NAME = "qw_productid"; 
    private static final String ENV_FILTER_FIELD_NAME = "qw_productid";
    private static final String CATEGORY_FIELD_IN_SUBCATEGORY_ENTITY = "qw_categoryid"; 
    private static final String TICKET_ENTITY = "ticket.ticket";
    private static final String INTER_TICKET_ENTITY = "inter_ticket.linkset";
    private static final String INTER_TICKET_FILTER_FIELD = "qw_ticketid";
    private static final String TICKETEVENT_ENTITY = "ticketevent.ticket";
    private static final String TICKETEVENT_FILTER_FIELD = "qw_ticketid";
    private static final String ATTACHMENT_OBJECTS_ENTITY  = "attachment_objects.ticket";
    private static final String ATTACHMENT_OBJECT_ID = "object_id";

    private ListboxFieldData oldCategoryData = null;
    private FieldData[] initialFieldsData = null;
    private String curOriginInteractionId = "0";

    protected HashMap replyInitVals;
    private ReplyComposeDialog replyDialog;

    /*
     * Interaction and AttachmentTicket form ids
     * It should initialized in HandlerFactory or it's siblings
     */
    private String interFormId, attachTicketFormId, solutionFormId, eventFormId;

    // Ties with other handlers
    private InteractionHandler interHandler;
    private AttachmentTicketHandler attachHandler;
    private SolutionHandler solutionHandler;
    private TicketEventHandler eventHandler;

    private String eventId;
    //private String externalEQLFilter = "";

    //void setExternalEQLFilter(String eqlFilter){
    //    externalEQLFilter = eqlFilter;
    //}

    private static final Set allowedStatus = new HashSet();

    static {
        allowedStatus.add(new Long(TicketHelper.NEW_STATUS));
        allowedStatus.add(new Long(TicketHelper.ASSIGNED_STATUS));
        allowedStatus.add(new Long(TicketHelper.OWNED_STATUS));
    }

    public void searchRecords(Collection entitiesFilters,
                              GridSearchProperties props,
                              boolean isLocalSearch) {
        super.searchRecords(entitiesFilters, props, isLocalSearch);
        eventId = null;
    }

    public void handleCustomMenuEvent(String eventId) {
        if(eventId == null) {
            return;
        }
        FamgMeta.Index formIndex = getFormIndex();
        //Set event for future use.
        this.eventId = eventId;
        if(eventId.equals(MY_QUEUES) || eventId.equals(MY_TICKETS) || eventId
                .equals(OPEN_TICKETS)) {
            FormOperations formContext = getOperationContext()
                    .getFormOperations();
            if(eventId.equals(MY_QUEUES)) {
                EntityReferenceData erd = new EntityReferenceData(OWNER_FIELD_NAME);
                erd.setSelectedRowID(new Long(getUserId()));
                addExternalFilter(
                        new EntityData(getTicketEntity(), new Long(-1),
                                new FieldData[]{erd}));
            } else if(eventId.equals(MY_TICKETS)) {
                EntityReferenceData erd = new EntityReferenceData(AGENT_FIELD_NAME);
                erd.setSelectedRowID(new Long(getUserId()));
                addExternalFilter(
                        new EntityData(getTicketEntity(), new Long(-1),
                                new FieldData[]{erd}));
            } else if(eventId.equals(OPEN_TICKETS)) {
                ListboxFieldData lbfd = new ListboxFieldData(STATUS_FIELD_NAME,
                        new SubsetData(CollectionsHelper.createIncrementalArray(
                                TicketHelper.CLOSED_STATUS, 0)));
                addExternalFilter(
                        new EntityData(getTicketEntity(), new Long(-1),
                                new FieldData[]{lbfd}));
            }
            formContext.clearForm(formIndex, true);
            getOperationContext().performOperation(
                    OperationTypes.SEARCH_RECORDS, formIndex);
        }
        if(eventId.equals(ACCEPT_TICKET)) {
            // check all custom dependances(conditions)
            if(checkDependences(formIndex)) {
                getOperationContext().performOperation(
                        OperationTypes.LOCK_AND_EDIT_RECORD, formIndex);
            }
        }
    }

    private boolean checkDependences(FamgMeta.Index formIndex) {
        FormOperations formContext = getOperationContext().getFormOperations();
        int state = formContext.getFormState(formIndex);
        if(state != FormState.SELECTED_STATE) {
            return false;
        }

        int type = getOperationContext().getMetaData().getFamgMeta(formIndex)
                .getForm().getEntityMeta().getField(STATUS_FIELD_NAME).getDataType();
        if(type == FieldMeta.LISTBOX) {
            //get current status
            FieldData statusField = formContext.getFieldData(formIndex, STATUS_FIELD_NAME);
            long curStatus = ((ListboxFieldData) statusField).getItemsSelected()
                    .getSelectedIDs()[SELECTED_INDEX];
            if(!allowedStatus.contains(new Long(curStatus))) {
                return false;
            }
        }
        FieldData ownerField = formContext.getFieldData(formIndex, OWNER_FIELD_NAME);
        if(ownerField instanceof EntityReferenceData) {
            Long selRowId = ((EntityReferenceData) ownerField)
                    .getSelectedRowID();
            if(selRowId != null && getUserId() != selRowId.longValue()) {
                if(DialogHelper.showModalQuestionDialog(CHANGE_OWNER_QUESTION)
                        == DialogHelper.NO) {
                    return false;
                }
            }
        }

        return true;
    }

    private long getUserId() {
        return getOperationContext().getMetaData().getUserProfile().getUserID();
    }

    private String getUserFullname() {
        return getOperationContext().getMetaData().getUserProfile()
                .getFullName();
    }

    public boolean processControlDataRequest(FieldDataRequest request) {
        FamgMeta.Index formIndex = getFormIndex();
        FormOperations context = getOperationContext().getFormOperations();
        String elementID = request.getElementID();
        if(COMPONENT_ID_FIELD_NAME.equalsIgnoreCase(elementID)) {
            EntityReferenceDataRequest theRequest
                    = (EntityReferenceDataRequest) request;
            FieldData productData = context.getFieldData(formIndex,
                    PRODUCT_ID_FIELD_NAME);
            FieldData cloned = productData.cloneData();
            cloned.setFieldID(COMPONENT_FILTER_FIELD_NAME);
            theRequest.setAdditionalFilterForRequestingEntity(cloned);
        } else if(REP_BVERSION_ID_FIELD_NAME.equalsIgnoreCase(elementID)) {
            EntityReferenceDataRequest theRequest
                    = (EntityReferenceDataRequest) request;
            FieldData productData = context.getFieldData(formIndex,
                    PRODUCT_ID_FIELD_NAME);
            FieldData cloned = productData.cloneData();
            cloned.setFieldID(BVERSION_FILTER_FIELD_NAME);
            theRequest.setAdditionalFilterForRequestingEntity(cloned);
        } else if(RES_BVERSION_ID_FIELD_NAME.equalsIgnoreCase(elementID)) {
            EntityReferenceDataRequest theRequest
                    = (EntityReferenceDataRequest) request;
            FieldData productData = context.getFieldData(formIndex,
                    PRODUCT_ID_FIELD_NAME);
            FieldData cloned = productData.cloneData();
            cloned.setFieldID(BVERSION_FILTER_FIELD_NAME);
            theRequest.setAdditionalFilterForRequestingEntity(cloned);
        } else if(REP_ENV_ID_FIELD_NAME.equalsIgnoreCase(elementID)) {
            EntityReferenceDataRequest theRequest
                    = (EntityReferenceDataRequest) request;
            theRequest
                    .clearAdditionalFilter();//clear previous filters, because it might be singleton-event-object.

            FieldData productData = context.getFieldData(formIndex,
                    PRODUCT_ID_FIELD_NAME);
            if(!productData.isEmpty()) {
                FieldData cloned = productData.cloneData();
                cloned.setFieldID(ENV_FILTER_FIELD_NAME);
                theRequest.addAdditionalFilterForRequestingEntity(cloned);
            }
            EntityReferenceData customerIdData = (EntityReferenceData) context
                    .getFieldData(
                            formIndex, CUSTOMER_ID_FIELD_NAME);
            if(customerIdData.getSelectedRowID() != null) {
                FieldData data = new TextboxFieldData(
                        CUSTOMER_TICKET_ENTITY_PKEYFIELD_NAME,
                        customerIdData.getSelectedRowID().toString());
                theRequest.addAdditionalFilter(data,
                        CUSTOMER_TICKET_ENTITY_NAME);
            }
        } else if(TEST_ENV_ID_FIELD_NAME.equalsIgnoreCase(elementID)) {
            EntityReferenceDataRequest theRequest
                    = (EntityReferenceDataRequest) request;
            FieldData productData = context.getFieldData(formIndex,
                    PRODUCT_ID_FIELD_NAME);
            //FieldData customerData = form.getModel().getElementData(CUSTOMER_ID_FIELD_NAME);
            FieldData cloned = productData.cloneData();
            //FieldData cloned_cust = (FieldData) customerData.cloneData();
            cloned.setFieldID(ENV_FILTER_FIELD_NAME);
            //cloned_cust.setFieldID(ENVCUST_FILTER_FIELD_NAME);
            theRequest.setAdditionalFilterForRequestingEntity(cloned);
            //theRequest.setAdditionalFilter(cloned_cust);
        } else if(SUB_CATEGORY_FIELD_NAME.equalsIgnoreCase(elementID)) {
            ListboxDataRequest listBoxReq = (ListboxDataRequest) request;
            ListboxFieldData categoryData = (ListboxFieldData) context
                    .getFieldData(formIndex, CATEGORY_FIELD_NAME);
            boolean isChange = OperationsHelper.compareFieldData(oldCategoryData, categoryData);
            if(!isChange) {
                return BREAK;
            }
            //if(!categoryData.isEmpty()) {
            FieldData cloned = categoryData.cloneData();
            cloned.setFieldID(CATEGORY_FIELD_IN_SUBCATEGORY_ENTITY);
            listBoxReq.setAdditionalFilter(cloned);
            //}
            oldCategoryData = (ListboxFieldData) categoryData.cloneData();
        }
        return CONTINUE;
    }

    public void setInitialFieldsData(FieldData[] fieldsData) {
        initialFieldsData = fieldsData;
    }

    protected void lockAndEditResponse(boolean success,
                                       EntityData[] entitiesList,
                                       EntityData[] externalFieldsList,
                                       Collection gridData) {

        super.lockAndEditResponse(success, entitiesList, externalFieldsList,
                gridData);

        if(!success || eventId == null) {
            return;
        }

        FamgMeta.Index formIndex = getFormIndex();
        FormOperations context = getOperationContext().getFormOperations();
        EntityReferenceData ownerField = new EntityReferenceData(OWNER_FIELD_NAME);
        ownerField.setSelectedRowID(new Long(getUserId()));
        ownerField.setSelectedFilter(getUserFullname());
        context.setFieldData(formIndex, ownerField);

        ListboxFieldData statusField = new ListboxFieldData(STATUS_FIELD_NAME,
                new SubsetData(new long[]{STATUS_OWNED}));
        context.setFieldData(formIndex, statusField);

        //EntityReferenceData ownerField = (EntityReferenceData) context.getFieldData(OWNER, index);
        //ListboxFieldData statusField = (ListboxFieldData) context.getFieldData(STATUS, index);
        //statusField.setItemsSelected(new SubsetData(new long[]{STATUS_OWNED}));
        //ownerField.setSelectedRowID(new Long(getUserId()));
        //ownerField.setSelectedFilter(getUserFullname());
        eventId = null;

    }

    protected void createRecordProtorypeResponse(boolean success,
                                                 FieldData[] fields,
                                                 Long rowId) {
        super.createRecordProtorypeResponse(success, fields, rowId);

        if(!success) {
            return;
        }

        FamgMeta.Index formIndex = getFormIndex();
        if(initialFieldsData != null && initialFieldsData.length > 0) {
            FormOperations formContext = getOperationContext()
                    .getFormOperations();
            for(int i = 0; i < initialFieldsData.length; i++) {
                if(initialFieldsData[i] != null) {
                    formContext.setFieldData(formIndex, initialFieldsData[i]);
                }
            }
            String originInterId = ((TextboxFieldData) formContext.getFieldData(
                    formIndex, CUR_INTERACTION_ID_FIELD)).getText();
            curOriginInteractionId = (originInterId != null) ? originInterId
                    :"0";
            initialFieldsData = null;
        } else {
            curOriginInteractionId = "0";
        }
    }

    protected void insertRecordResponse(boolean success,
                                        EntityData[] entitiesList,
                                        EntityData[] externalFieldsList,
                                        Collection gridData,
                                        RowData updatedRow) {
        super.insertRecordResponse(success, entitiesList, externalFieldsList,
                gridData, updatedRow);

        FormOperations formContext = getOperationContext().getFormOperations();

        if(!success) {
            return;
        }
        if(!curOriginInteractionId.equals("0")) {
            FamgMeta.Index formIndex = getFormIndex();
            long ticketId = formContext.getSelectedRecordId(formIndex)
                    .longValue();
            
            FamgMeta.Index interactionIndex = (FamgMeta.Index) getOperationContext()
                .getMetaData().getIndexByID(interFormId);

            String interId = ((TextboxFieldData) formContext.getFieldData(
                    interactionIndex, INTERACTION_ID_FIELD)).getText();
            if(FormState.NEW_STATE == getOperationContext().getFormOperations()
                    .getFormState(interactionIndex) &&
                    curOriginInteractionId.equals(interId)) {
                linkToTicketDataset(interactionIndex, ticketId);
            }
            curOriginInteractionId = "0";
        }
    }

    private void linkToTicketDataset(FamgMeta.Index interationIndex, long ticketId) {
        FormOperations formContext = getOperationContext().getFormOperations();
        InFormGridFieldData linksData = 
            (InFormGridFieldData) formContext.getFieldData(interationIndex, LINKED_TICKETS_FIELD);
        GridData linksGridData = linksData.getGridData().cloneGrid();
        if(linksGridData.getRowByID(new Long(ticketId)) != null ){
            DialogHelper.showModalMessageDialog("The link to Ticket # " + ticketId + " already exists.");
            return;
        }
        else{
            String[] cols = {""+ticketId};
            linksGridData.insertRow(new RowData(new Long(ticketId), cols));
        }
        linksData.setGridData(linksGridData);    
        formContext.setFieldData(interationIndex, linksData);
    }

    public void handleCustomButtonEvent(String buttonId) {
        FamgMeta.Index formIndex = getFormIndex();
        FormOperations formContext = getOperationContext().getFormOperations();
        int state = formContext.getFormState(formIndex);
        if(buttonId.equalsIgnoreCase(LINK_TO_INTERACTION_BUTTON)) {
            switch(state) {
                case FormState.SELECTED_STATE:
                case FormState.EDIT_STATE:
                    //DialogHelper.showModalMessageDialog("Under construction...");
                    linkTicketToInteraction(formIndex);
                    break;
                default:
                    DialogHelper.showModalMessageDialog(
                            "This button is available only in EDIT or SELECTED state.");
            }
        } else if(buttonId.equalsIgnoreCase(NEW_SOLUTION_BUTTON)) {
            switch(state) {
                case FormState.SELECTED_STATE:
                    createSolutionFromNewState(formIndex);
                    break;
                default:
                    DialogHelper.showModalMessageDialog(
                            "This button is available only in SELECTED state.");
                    break;
            }
        } else if(buttonId.equals(ATTACH_FILE_BUTTON)) {
            switch(state) {
                case FormState.SELECTED_STATE:
                    createNewAttachment(formIndex);
                    break;
                default:
                    DialogHelper.showModalMessageDialog(
                            "This button is available only in SELECTED state.");
            }
        } else if(buttonId.equals(SEND_EMAIL_BUTTON)) {
            switch(state) {
                case FormState.SELECTED_STATE:
                    sendReplyEmail(formIndex);
                    break;
                default:
                    DialogHelper.showModalMessageDialog(
                            "This button is available only in SELECTED state.");
            }
        }
    }

    protected void sendReplyEmail(FamgMeta.Index formIndex) {
        replyInitVals = new HashMap();

        FormOperations context = getOperationContext().getFormOperations();
        FieldData ticketIdFld = context.getFieldData(formIndex,
                TICKET_ID_FIELD_NAME);
        FieldData custIdFld = context.getFieldData(formIndex,
                CUSTOMER_ID_FIELD_NAME);
        FieldData empIdFld = context.getFieldData(formIndex,
                EMPLOYEE_ID_FIELD_NAME);
        FieldData subjectFld = context.getFieldData(formIndex,
                SUBJECT_FIELD_NAME);
        FieldData messageFld = context.getFieldData(formIndex,
                DESCRIPTION_FIELD_NAME);
        FieldData messageTextFld = context.getFieldData(formIndex,
                DESCRIPTION_TEXT_FIELD_NAME);
        
        int objectType = OperationsHelper.TICKET_OBJECT_TYPE;
        long objectId = Long.parseLong(
                ((TextboxFieldData) ticketIdFld).getText());

        String oldSubject = "";
        if(!subjectFld.isEmpty()) {
            oldSubject = ((TextboxFieldData) subjectFld).getText();
        }

        String newSubject = ("QueWeb " + TICKET_ID_CAPTION + objectId + " : "
                + oldSubject).substring(0, 255);
        replyInitVals.put(EmailComposeHelper.SUBJECT_MAP_FIELD, newSubject);
        Long initCustomerId = null;
        boolean isCustomer = false;
        if(!custIdFld.isEmpty()) {
            initCustomerId = ((EntityReferenceData) custIdFld)
                    .getSelectedRowID();
            isCustomer = true;
        } else if(!empIdFld.isEmpty()) {
            initCustomerId = ((EntityReferenceData) empIdFld)
                    .getSelectedRowID();
            isCustomer = false;
        }
        String oldMessage = "";
        if(!messageTextFld.isEmpty()) {
            oldMessage = ((MemoFieldData) messageTextFld).getText();
        }
        else if(!messageFld.isEmpty()) {
            oldMessage = ((TextareaFieldData) messageFld).getText();
        }
        if(initCustomerId != null) {
            FromAndToEmailAsyncCallback callback
                    = new FromAndToEmailAsyncCallback(objectType, objectId,
                    oldSubject, oldMessage);
            CustomRPC.getCustomRPC().getFromAndToEmail(objectType, objectId,
                    isCustomer, initCustomerId, callback);
        } else {
            DialogHelper.showModalMessageDialog(
                    "Can't get customer or internal custore to determine recipient address.");
        }
    }

    private void linkTicketToInteraction(FamgMeta.Index formIndex) {
        FormOperations context = getOperationContext().getFormOperations();
        Long ticketId = context.getSelectedRecordId(formIndex);
        FamgMeta.Index interactionIndex = (FamgMeta.Index) getOperationContext()
                .getMetaData().getIndexByID(interFormId);
        Long interId = context.getSelectedRecordId(interactionIndex);
        if(interId == null) {
            DialogHelper.showModalMessageDialog(
                    "Interaction Record must be selected on the Interaction Tab.\nPlease navigate to it, select desired Interaction and click Link again.");
        } else {
            int answer = DialogHelper.showModalQuestionDialog(
                    "The link between ticket # " + ticketId
                            + " and interaction # " + interId
                            + " is going to be created.");
            if(DialogHelper.YES == answer) {
                if(FormState.NEW_STATE == context.getFormState(
                        interactionIndex)) {
                    linkToTicketDataset(interactionIndex, ticketId.longValue());
                } else {
                    RPC.QAsyncCallback callback = new CreateLinkAsyncCallback();
                    CustomRPC.getCustomRPC().createTicketInteractionLink(
                            ticketId, interId, callback);
                }
            }
        }
    }

    private void createNewAttachment(FamgMeta.Index formIndex) {
        FormOperations formContext = getOperationContext().getFormOperations();
        FieldData ticketId = formContext.getFieldData(formIndex,
                TICKET_ID_FIELD_NAME);
        FieldData clonedTicketId = ticketId.cloneData();
        FieldData[] initData = new FieldData[6];
        initData[0] = clonedTicketId;

        attachHandler.setInitialFieldsData(initData);
        OperationsHelper.createNewRecord(attachTicketFormId,
                getOperationContext());
    }

    protected boolean processFilteredLink(String linkedForm, 
            FormOperations formContext, FamgMeta.Index formIndex){
        EntityData linkFilter;
        if(linkedForm.equalsIgnoreCase(interFormId)) { // the link for ticket form is pressed
            linkFilter = new EntityData(INTER_TICKET_ENTITY, new Long(-1), 
                    new FieldData[]{ new TextboxFieldData(INTER_TICKET_FILTER_FIELD, 
                            formContext.getSelectedRecordId(formIndex).toString()) });
            interHandler.addExternalFilter(linkFilter);
            return CONTINUE;
        }    
        if(linkedForm.equalsIgnoreCase(attachTicketFormId)) {
            linkFilter = new EntityData(ATTACHMENT_OBJECTS_ENTITY, new Long(-1),
                    new FieldData[]{ new TextboxFieldData(ATTACHMENT_OBJECT_ID,
                            formContext.getSelectedRecordId(formIndex).toString()) });
            attachHandler.addExternalFilter(linkFilter);
            return CONTINUE;
        }    
        if(linkedForm.equalsIgnoreCase(eventFormId)) {
            EntityReferenceData erd = new EntityReferenceData(TICKETEVENT_FILTER_FIELD);
            erd.setSelectedRowID(formContext.getSelectedRecordId(formIndex));
            linkFilter = new EntityData(TICKETEVENT_ENTITY, new Long(-1), new FieldData[]{ erd });
            eventHandler.addExternalFilter(linkFilter);
            return CONTINUE;
        } 
        return BREAK;
    }    
    
    protected String checkSolutionAllowance(FormOperations context, FamgMeta.Index formIndex){
        String errMsg = "This button is available only if ticket status " +
                        "is release candidate, delivered or closed.";
        FieldData ticketStatus = context.getFieldData(formIndex, STATUS_FIELD_NAME);
        if(!ticketStatus.isEmpty()) {
            long selId = ((ListboxFieldData) ticketStatus).getItemsSelected()
                    .getSelectedIDs()[0];
            switch((int) selId) {
                case TicketHelper.RELEASE_CANDIDATE_STATUS:
                case TicketHelper.DELIVERED_STATUS:
                case TicketHelper.CLOSED_STATUS:
                    break;
                default:
                    return errMsg;
            }
        } else {
            return errMsg;
        }
        return "";
    }

    protected FieldData[] prepareSolutionInitialData(FormOperations context, FamgMeta.Index formIndex) {
        FieldData ticketId = context.getFieldData(formIndex, TICKET_ID_FIELD_NAME);
        FieldData ticketProduct = context.getFieldData(formIndex, PRODUCT_ID_FIELD_NAME);
        FieldData ticketComponent = context.getFieldData(formIndex, COMPONENT_ID_FIELD_NAME);
        FieldData ticketSubject = context.getFieldData(formIndex, SUBJECT_FIELD_NAME);
        FieldData ticketDesc = context.getFieldData(formIndex, DESCRIPTION_FIELD_NAME);
        FieldData ticketDescText = context.getFieldData(formIndex, DESCRIPTION_TEXT_FIELD_NAME);
        FieldData ticketResp = context.getFieldData(formIndex, RESPONSE_FIELD_NAME);
        FieldData ticketRespText = context.getFieldData(formIndex, RESPONSE_TEXT_FIELD_NAME);

        FieldData clonedTicketId = ticketId.cloneData();
        clonedTicketId.setFieldID(SOLUTION_CUR_TICKET_ID_FIELD);

        FieldData clonedProduct = null;
        FieldData clonedComponent = null;
        FieldData clonedSubject = null;
        FieldData clonedDesc = null;
        FieldData clonedDescText = null;
        FieldData clonedResp = null;
        FieldData clonedRespText = null;

        if (!ticketProduct.isEmpty()) {
            clonedProduct = ticketProduct.cloneData();
            clonedProduct.setFieldID(SOLUTION_PRODUCT_FIELD);
        }
        if (!ticketComponent.isEmpty()) {
            clonedComponent = ticketComponent.cloneData();
            clonedComponent.setFieldID(SOLUTION_COMPONENT_FIELD);
        }
        if (!ticketSubject.isEmpty()) {
            clonedSubject = ticketSubject.cloneData();
            clonedSubject.setFieldID(SOLUTION_SUMMARY_FIELD);
        }
        if (!ticketDesc.isEmpty()) {
            clonedDesc = ticketDesc.cloneData();
            clonedDesc.setFieldID(SOLUTION_PROBLEM_FIELD);
        }
        if (!ticketDescText.isEmpty()) {
            clonedDescText = ticketDescText.cloneData();
            clonedDescText.setFieldID(SOLUTION_PROBLEM_TEXT_FIELD);
        }
        if (!ticketResp.isEmpty()) {
            clonedResp = ticketResp.cloneData();
            clonedResp.setFieldID(SOLUTION_SOL_FIELD);
        }
        if (!ticketRespText.isEmpty()) {
            clonedRespText = ticketRespText.cloneData();
            clonedRespText.setFieldID(SOLUTION_SOL_TEXT_FIELD);
        }
        FieldData[] initData = new FieldData[8];
        initData[0] = clonedTicketId;
        initData[1] = clonedProduct;
        initData[2] = clonedComponent;
        initData[3] = clonedSubject;
        initData[4] = clonedDesc;
        initData[5] = clonedDescText;
        initData[6] = clonedResp;
        initData[7] = clonedRespText;
        return initData;
    } 
    
    protected void createSolutionFromNewState(FamgMeta.Index formIndex) {
        FormOperations context = getOperationContext().getFormOperations();
        String wrongStatus = checkSolutionAllowance(context, formIndex);
        if (wrongStatus.length() > 0) {
            DialogHelper.showModalMessageDialog(wrongStatus);
            return;
        }
        initializeHandler(prepareSolutionInitialData(context, formIndex));
    }

    protected void initializeHandler(FieldData[] initData) {
        solutionHandler.setInitialFieldsData(initData);
        OperationsHelper.createNewRecord(solutionFormId, getOperationContext());
    }

    public void setSolutionHandler(SolutionHandler solutionHandler) {
        this.solutionHandler = solutionHandler;
    }

    public void setAttachHandler(AttachmentTicketHandler attachHandler) {
        this.attachHandler = attachHandler;
    }

    public void setInterHandler(InteractionHandler interHandler) {
        this.interHandler = interHandler;
    }

    public void setInterFormId(String interFormId) {
        this.interFormId = interFormId;
    }

    public void setTicketEventHandler(TicketEventHandler eventHandler) {
        this.eventHandler = eventHandler;
    }

    public void setTicketEventFormId(String eventFormId) {
        this.eventFormId = eventFormId;
    }

    public void setAttachTicketFormId(String attachTicketFormId) {
        this.attachTicketFormId = attachTicketFormId;
    }

    public void setSolutionFormId(String solutionFormId) {
        this.solutionFormId = solutionFormId;
    }

    public String getTicketEntity() {
        return TICKET_ENTITY;
    }

    protected class FromAndToEmailAsyncCallback extends RPC.QAsyncCallback {
        int objectType;
        long objectId;
        String oldMessage;
        String oldSubject;

        public FromAndToEmailAsyncCallback(int objType, long objId,
                                           String subject, String text) {
            objectType = objType;
            objectId = objId;
            oldSubject = subject;
            oldMessage = text;
        }

        public void onRequestEnded(boolean success, Object result) {
            if(success) {
                boolean isOk = true;
                String fromAdr = "";
                String toAdr = "";
                if(result == null) {
                    isOk = false;
                } else if(!(result instanceof String[])) {
                    isOk = false;
                } else {
                    String[] retEmails = (String[]) result;
                    if(retEmails.length != 2) {
                        isOk = false;
                    } else {
                        fromAdr = retEmails[0];
                        toAdr = retEmails[1];
                        if(StringUtil.isStringEmpty(fromAdr) || StringUtil
                                .isStringEmpty(toAdr)) {
                            isOk = false;
                        }
                    }
                }
                if(!isOk) {
                    DialogHelper.showModalMessageDialog(
                            "Can't get email adresses. Reply can't be sent.");
                    return;
                }
                
                String newBody = "<br><hr><b>From: </b>" + toAdr +
                "<br><b>Subject: </b>" + oldSubject + "<br>"+
                "<br><b>Description: </b><br>";

                if(!StringUtil.isStringEmpty(oldMessage)) {
                    if(!HtmlEditFrame.isHTML(oldMessage)) {
                        newBody = "\n----------------------------------------" +
                                StringUtil.htmlToText(newBody);
                    }
                    newBody += oldMessage;
                } else {
                    newBody += HtmlEditFrame.HTML_INDICATOR;
                }
                
                //String newBody = "\n----------------------------------------" +
                //        "\nFrom: " + toAdr +
                //        "\nSubject: " + oldSubject +
                //        "\nDescription:\n" + oldMessage;

                replyInitVals.put(EmailComposeHelper.FROM_MAP_FIELD, fromAdr);
                replyInitVals.put(EmailComposeHelper.TO_MAP_FIELD, toAdr);
                replyInitVals.put(EmailComposeHelper.BODY_MAP_FIELD, newBody);

                if(replyDialog == null) {
                    replyDialog = new ReplyComposeDialog("Send Email Form");
                }
                replyDialog.setInitialDataMap(replyInitVals);
                replyDialog.setObjectType(objectType);
                replyDialog.setObjectId(objectId);
                replyDialog.show(true);
            } else {
                DialogHelper.showModalMessageDialog(
                        "RPC call failed. Reply can't be sent.");
            }
        }
    }

    private class CreateLinkAsyncCallback extends RPC.QAsyncCallback {
        public CreateLinkAsyncCallback() {
        }

        public void onRequestEnded(boolean success, Object result) {
            if(success) {
                Boolean rv = (Boolean) result;
                if(rv != null) {
                    if(rv == Boolean.FALSE) {
                        DialogHelper.showModalMessageDialog(
                                "The link already exists.");
                    } else {
                        DialogHelper.showModalMessageDialog(
                                "The link is created.");
                    }
                }
            } else {
                DialogHelper.showModalMessageDialog("RPC call failed.");
            }
        }
    }
}
