/*
 * 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.core.client.frames.email;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FormHandler;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormSubmitEvent;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.jpavel.gwt.wysiwyg.client.EditorToolbar;
import com.jpavel.gwt.wysiwyg.client.events.ImageAttached;
import com.queplix.core.client.app.vo.MemoFieldMeta;
import com.queplix.core.client.common.StringUtil;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventListener;
import com.queplix.core.client.common.ui.DialogHelper;
import com.queplix.core.client.common.ui.OkayCancelPopup;
import com.queplix.core.client.common.ui.resizable.Resizable;
import com.queplix.core.client.common.ui.upload.QFileUpload;
import com.queplix.core.client.common.ui.upload.QFileUploadListener;
import com.queplix.core.client.controls.QFormElement;
import com.queplix.core.client.controls.entityreference.QEntityReference;
import com.queplix.core.client.controls.memo.QMemo;
import com.queplix.core.client.frames.htmledit.HtmlEditFrame;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

/**
 * @author Alexander Melnik
 * @since 12 Mar 2007
 */
public class EmailComposeFrame extends VerticalPanel
        implements Resizable, ClickListener {
    public static final int MIN_WIDTH = 700;
    public static final int MIN_HEIGHT = 300;

    private long process_id;

    private VerticalPanel mainPanel;
    private HorizontalPanel topPanel;

    private HorizontalPanel rowTwo;
    private HorizontalPanel rowFour;

    private TextBox from;
    private Label toL;
    private TextBox to;
    private TextBox cc;
    private Label subjectL;
    private TextBox subject;

    private QEntityReference template;

    private ListBox attachments;

    private Button add;
    private Button delete;

    private QMemo memo;

    private Button checkSpelling;

    private OkayCancelPopup attachmentDialog;
    private QFileUpload fileUpload;

    private FormPanel deleteForm;
    private ArrayList attachmentsIds;

    private HashMap initMap = new HashMap();

    private HashMap hiddenAttachments = new HashMap();
    private ArrayList usedAttachments;
    private FormPanel deleteHiddenAttachmentsForm;

    public EmailComposeFrame(String userEmail) {
        createFrame(false, true);
        // set initial value
        from.setText(userEmail);
    }

    public EmailComposeFrame(boolean isFromEnabled, boolean isSubjectEnabled) {
        createFrame(isFromEnabled, isSubjectEnabled);
    }

    public void setInitialMap(HashMap initMap) {
        this.initMap = initMap;
    }
    
    /**
     * Creates GUI components.
     *
     * @param isFromEnabled indicates if from field is enabled.
     * @param isSubjectEnabled indicates if subject field is enabled.
     */
    private void createFrame(boolean isFromEnabled, boolean isSubjectEnabled) {
        VerticalPanel vp = new VerticalPanel();
        vp.setWidth("100%");

        topPanel = new HorizontalPanel();
        topPanel.setWidth("100%");
        topPanel.add(vp);

        HorizontalPanel rowOne = new HorizontalPanel();
        rowOne.setWidth("100%");
        vp.add(rowOne);
        Label fromL = new Label("From");
        fromL.setStyleName("form_formElement");
        rowOne.add(fromL);
        rowOne.setCellWidth(fromL, "44px");
        rowOne.setCellVerticalAlignment(fromL,
                HasVerticalAlignment.ALIGN_MIDDLE);
        from = new TextBox();
        from.setEnabled(isFromEnabled);
        from.setStyleName("styled_input");
        from.setWidth("100%");
        rowOne.add(from);

        rowTwo = new HorizontalPanel();
        rowTwo.setWidth("100%");
        vp.add(rowTwo);
        toL = new Label("To");
        rowTwo.add(toL);
        rowTwo.setCellWidth(toL, "44px");
        rowTwo.setCellVerticalAlignment(toL, HasVerticalAlignment.ALIGN_MIDDLE);
        to = new TextBox();
        to.setStyleName("styled_input");
        to.setWidth("100%");
        rowTwo.add(to);
        to.addChangeListener(new ChangeListener() {
            public void onChange(Widget sender) {
                if (to.getText().trim().equals("")) {
                    toL.setStyleName("form_formElementRequiredColor");
                } else {
                    toL.setStyleName("form_formElement");
                }
            }
        });
        
        HorizontalPanel rowThree = new HorizontalPanel();
        rowThree.setWidth("100%");
        vp.add(rowThree);
        Label ccL = new Label("CC");
        ccL.setStyleName("form_formElement");
        rowThree.add(ccL);
        rowThree.setCellWidth(ccL, "44px");
        rowThree.setCellVerticalAlignment(ccL,
                HasVerticalAlignment.ALIGN_MIDDLE);
        cc = new TextBox();
        cc.setWidth("100%");
        cc.setStyleName("styled_input");
        rowThree.add(cc);

        rowFour = new HorizontalPanel();
        rowFour.setWidth("100%");
        vp.add(rowFour);
        subjectL = new Label("Subject");
        rowFour.add(subjectL);
        rowFour.setCellWidth(subjectL, "44px");
        rowFour.setCellVerticalAlignment(subjectL,
                HasVerticalAlignment.ALIGN_MIDDLE);
        subject = new TextBox();
        subject.setEnabled(isSubjectEnabled);
        subject.setWidth("100%");
        subject.setStyleName("styled_input");
        rowFour.add(subject);
        subject.addChangeListener(new ChangeListener() {
            public void onChange(Widget sender) {
                if (subject.getText().trim().equals("")) {
                    subjectL.setStyleName("form_formElementRequiredColor");
                } else {
                    subjectL.setStyleName("form_formElement");
                }
            }
        });

        //for future relise
        //EntityReferenceMeta entityReferenceMeta = new EntityReferenceMeta("", "Template", new GridMeta(), "entity");
        //template = new QEntityReference(entityReferenceMeta, QFormElement.HORIZONTAL);
        //template.getBaseView().setVisible(false);
        //vp.add(template.getBaseView());
        //vp.setCellHorizontalAlignment(template.getBaseView(), HasHorizontalAlignment.ALIGN_RIGHT);

        Label attachmentsL = new Label("Attachments");
        attachments = new ListBox();
        attachments.setStyleName("styled_input");
        attachments.setVisibleItemCount(4);
        attachments.setWidth("200px");

        VerticalPanel attachmentsPanel = new VerticalPanel();
        attachmentsPanel.add(attachmentsL);
        attachmentsPanel.add(attachments);

        HorizontalPanel addDeletePanel = new HorizontalPanel();
        attachmentsPanel.add(addDeletePanel);
        attachmentsPanel.setCellHorizontalAlignment(addDeletePanel,
                HasHorizontalAlignment.ALIGN_RIGHT);

        add = new Button("Add");
        addDeletePanel.add(add);
        add.setWidth("80px");
        addDeletePanel.setCellWidth(add, "80px");
        delete = new Button("Delete");
        addDeletePanel.add(delete);
        delete.setWidth("80px");
        addDeletePanel.setCellWidth(delete, "80px");
        addDeletePanel.setCellHorizontalAlignment(add,
                HasHorizontalAlignment.ALIGN_RIGHT);
        addDeletePanel.setCellHorizontalAlignment(delete,
                HasHorizontalAlignment.ALIGN_RIGHT);

        topPanel.add(attachmentsPanel);
        topPanel.setCellWidth(attachmentsPanel, "200px");
        topPanel.setCellVerticalAlignment(attachmentsPanel,
                HasVerticalAlignment.ALIGN_BOTTOM);
        topPanel.setCellHorizontalAlignment(attachmentsPanel,
                HasHorizontalAlignment.ALIGN_RIGHT);

        _initMemo();
        //checkSpelling = new Button("Check Spelling");

        mainPanel = new VerticalPanel();
        mainPanel.setWidth("100%");
        mainPanel.add(topPanel);
        mainPanel.add(memo.getView().getActiveControl());
        //mainPanel.add(checkSpelling);
        //mainPanel.setCellHorizontalAlignment(checkSpelling, HasHorizontalAlignment.ALIGN_RIGHT);

        add(mainPanel);

        addListeners();
    }

    public void initMemo() {
        _initMemo();
        mainPanel.remove(1);
        mainPanel.insert(memo.getView().getActiveControl(), 1);
    }

    private void _initMemo() {
        MemoFieldMeta memoMeta = new MemoFieldMeta("", "", "", "",
                MemoFieldMeta.EDIT_TYPE);
        memoMeta.setInline(true);
        memo = new QMemo(memoMeta, QFormElement.HORIZONTAL);
        memo.getView().setEnabledForNew();
        getHtmlEditFrame().setAddLinkAsAttachment(true);
        memo.getView().getEventSource().addEventListener(new EventListener() {
            public void onEvent(Event event, Widget sender) {
                if(event == EditorToolbar.Events.IMAGE_ATTACHED) {
                    ImageAttached data = (ImageAttached) event.getData();
                    hiddenAttachments.put(data.fileName, data.id);
                }
            }
        });
    }

    private void addListeners() {
        //checkSpelling.addClickListener(this);
        add.addClickListener(this);
        delete.addClickListener(this);
    }

    public void onClick(Widget sender) {
        if(sender == checkSpelling) {
            validate();
        } else if(sender == add) {
            initAttachmentDialog();
            attachmentDialog.show();
        } else if(sender == delete) {
            int index = attachments.getSelectedIndex();
            if(index == -1) {
                DialogHelper.showModalMessageDialog(
                        EmailComposeHelper.ERR_MSG_NO_ACTIVE_RECORD);
            } else {
                deleteAttachment(index);
            }
        }
    }

    private void initAttachmentDialog() {
        if(attachmentDialog == null) {
            attachmentsIds = new ArrayList();
        }
        fileUpload = new QFileUpload(getAction(), false);
        fileUpload.addQFileUploadListener(new QFileUploadListener() {
            public void onFileUploaded(Widget sender, String id) {
                attachmentsIds.add(id);
                attachments.addItem(fileUpload.getFileUploadName());
                attachmentDialog.hide();
            }
        });
        attachmentDialog = new OkayCancelPopup(
                EmailComposeHelper.ATTACHMENT_CAPTION, true);
        attachmentDialog.getEventSource().addEventListener(new EventListener() {
            public void onEvent(Event event, Widget sender) {
                if(event == OkayCancelPopup.Events.OK) {
                    fileUpload.submitUpload();
                } else if(event == OkayCancelPopup.Events.CANCEL) {
                    attachmentDialog.hide();
                }
            }
        });
        attachmentDialog.setWidget(fileUpload);
    }

    private String getAction() {
        return "../attachmentUpload/saveTemp?process_id=" + process_id;
    }

    private void deleteAttachment(final int index) {
        if(deleteForm == null) {
            deleteForm = new FormPanel();
            mainPanel.add(deleteForm);
            deleteForm.addFormHandler(new FormHandler() {
                public void onSubmit(FormSubmitEvent event) {
                }

                public void onSubmitComplete(FormSubmitCompleteEvent event) {
                    attachmentsIds.remove(index);
                    attachments.removeItem(index);
                }
            });
        }
        deleteForm.setMethod(FormPanel.METHOD_POST);
        deleteForm.setAction(
                "../attachmentUpload/deleteTemp?id=" + attachmentsIds.get(
                        index));
        deleteForm.submit();
    }

    public boolean validate() {
        boolean isToValid = !to.getText().trim().equals("");
        boolean isSubjectValid = !subject.getText().trim().equals("");
        if(!isToValid || !isSubjectValid) {
            String errMsg = EmailComposeHelper.ERR_MSG_EMPTY_FIELDS + "\r\n";
            if(!isToValid) {
                toL.setStyleName("form_formElementRequiredColor");
                errMsg += "[" + toL.getText() + "]";
            } else {
                toL.setStyleName("form_formElement");
            }
            if(!isSubjectValid) {
                subjectL.setStyleName("form_formElementRequiredColor");
                errMsg += "\r\n[" + subjectL.getText() + "]";
            } else {
                subjectL.setStyleName("form_formElement");
            }
            DialogHelper.showModalMessageDialog(errMsg + ".");
            return false;
        } else {
            toL.setStyleName("form_formElement");
            subjectL.setStyleName("form_formElement");
        }
        return true;
    }

    public void resetInput() {
        _resetInput();
        memo.getModel().getData().setText("");
        HtmlEditFrame htmlEditFrame = getHtmlEditFrame();
        htmlEditFrame.setText("");
        htmlEditFrame.toggleView(true);
    }
    
    private void _resetInput() {
        setProcess_id(System.currentTimeMillis());
        getHtmlEditFrame().setImageAttachmentAction(getAction());
        if(fileUpload != null) {
            fileUpload.setAction(getAction());
        }
        to.setText("");
        toL.setStyleName("form_formElementRequiredColor");
        cc.setText("");
        subject.setText("");
        subjectL.setStyleName("form_formElementRequiredColor");
        attachments.clear();
    }

    public void setInitialData() {
        _resetInput();
        if(initMap == null || initMap.size() == 0) {
            return;
        }
        // set initial values
        String initFrom = (String) initMap.get(
                EmailComposeHelper.FROM_MAP_FIELD);
        if(!StringUtil.isStringEmpty(initFrom)) {
            from.setText(initFrom);
        }
        String initTo = (String) initMap.get(EmailComposeHelper.TO_MAP_FIELD);
        if(!StringUtil.isStringEmpty(initTo)) {
            to.setText(initTo);
        }
        String initCc = (String) initMap.get(EmailComposeHelper.CC_MAP_FIELD);
        if(!StringUtil.isStringEmpty(initCc)) {
            cc.setText(initCc);
        }
        String initSbj = (String) initMap.get(
                EmailComposeHelper.SUBJECT_MAP_FIELD);
        if(!StringUtil.isStringEmpty(initSbj)) {
            subject.setText(initSbj);
        }
        String initBody = (String) initMap.get(
                EmailComposeHelper.BODY_MAP_FIELD);
        if(!StringUtil.isStringEmpty(initBody)) {
            HtmlEditFrame actCtrl = (HtmlEditFrame) memo.getView()
                    .getActiveControl();
            memo.getModel().getData().setText(initBody);
            ///actCtrl.setupEditor(initBody);
            actCtrl.toggleView(HtmlEditFrame.isHTML(initBody));
            actCtrl.setText(initBody);
            actCtrl.setOffsetWidth(HtmlEditFrame.DEFAULT_WIDTH);
            actCtrl.setOffsetHeight(HtmlEditFrame.DEFAULT_HEIGHT);
        }
    }

    public void setOffsetHeight(int height) {
        if(MIN_HEIGHT > height) {
            height = MIN_HEIGHT;
        }
        mainPanel.setHeight(height + "px");
        memo.getView().setOffsetHeight(height - topPanel.getOffsetHeight());
    }

    public void setOffsetWidth(int width) {
        if(MIN_WIDTH > width) {
            width = MIN_WIDTH;
        }
        String w = width + "px";
        memo.getView().setOffsetWidth(width);
        setWidth(w);
        mainPanel.setWidth(w);
        topPanel.setWidth(w);
    }

    public String getTo() {
        return to.getText();
    }

    public String getFrom() {
        return from.getText();
    }

    public String getSubject() {
        return subject.getText();
    }

    public String getCc() {
        return cc.getText();
    }

    public String getEmailBody(boolean processPlainTextAsHtml) {
        memo.getController().uploadDataToModel();

        String text = memo.getModel().getData().getText();

        if(getHtmlEditFrame().isShowFrame()) {
            text = EmailComposeHelper.replaceImagesSrc(text);
            removeUnusedHiddenAttachments(text);
        }

        if(processPlainTextAsHtml) {
            if(!getHtmlEditFrame().isShowFrame()) {
                text = "<pre>" + text + "</pre><!--html-->";
            }
        }

        return text;
    }

    public void removeUnusedHiddenAttachments(String text) {
        usedAttachments = new ArrayList();
        for(int i = 0; i < text.length() - 4; i++) {
            if(Character.toUpperCase(text.charAt(i)) == '<' &&
                    Character.toUpperCase(text.charAt(i + 1)) == 'I' &&
                    Character.toUpperCase(text.charAt(i + 2)) == 'M' &&
                    Character.toUpperCase(text.charAt(i + 3)) == 'G') {
                int start = i + 5;
                int end = text.indexOf('>', i + 3);
                processTag(text.substring(start, end + 1));
                i = end;
            }
        }
        for(int i = 0; i < usedAttachments.size(); i++) {
            hiddenAttachments.remove(usedAttachments.get(i));
        }
        for(Iterator i = hiddenAttachments.keySet().iterator(); i.hasNext();) {
            String name = (String) i.next();
            deleteAttachment((String) hiddenAttachments.get(name));
        }
        hiddenAttachments = new HashMap();
    }

    private void deleteAttachment(String id) {
        if(deleteHiddenAttachmentsForm == null) {
            deleteHiddenAttachmentsForm = new FormPanel();
            mainPanel.add(deleteHiddenAttachmentsForm);
        }
        deleteHiddenAttachmentsForm.setMethod(FormPanel.METHOD_POST);
        deleteHiddenAttachmentsForm.setAction(
                "../attachmentUpload/deleteTemp?id=" + id);
        deleteHiddenAttachmentsForm.submit();
    }

    public void processTag(String text) {
        int index = text.indexOf("src=\"cid:");
        if(index != -1) {
            int end = text.indexOf("\"", index + 9);
            String fileName = text.substring(index + 9, end);
            usedAttachments.add(fileName);
        }
    }

    public long getProcess_id() {
        return process_id;
    }

    public void setProcess_id(long process_id) {
        this.process_id = process_id;
    }

    private HtmlEditFrame getHtmlEditFrame() {
        return (HtmlEditFrame) memo.getView().getActiveControl();
    }
}
