/*
 * 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.htmledit;

import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.LoadListener;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.jpavel.gwt.wysiwyg.client.Editor;
import com.jpavel.gwt.wysiwyg.client.EditorToolbar;
import com.queplix.core.client.app.Application;
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.OkayCancelPopup;
import com.queplix.core.client.common.ui.resizable.Resizable;
import com.queplix.core.client.common.ui.resizable.ResizableScrollPanel;
import com.queplix.core.client.controls.datefield.DateHelper;
import com.queplix.core.client.controls.memo.QMemoModel;

import java.util.Date;

/**
 * HTML editor frame.
 *
 * @author Sultan Tezadov, Alexander Melnik
 * @since 23 Oct 2006
 */
public class HtmlEditFrame extends VerticalPanel
        implements EventListener, Resizable {
    public final static int MIN_WIDTH = 700;
    public final static int MIN_HEIGHT = 250;
    public final static int DEFAULT_WIDTH = 700;
    public final static int DEFAULT_HEIGHT = 250;

    private EventListener eventListener;
    private Editor editor;
    private String textToLoad;
    private boolean isEditorLoaded;
    private boolean isEnabled;
    private HTML lockedHTML; //for append and prepend

    private String lockedText;

    private ResizableScrollPanel rsp;

    private int memoType;

    private boolean isLockedTextHTML;

    private QMemoModel model;

    private static final String INDICATION_PREFIX_PLAINTEXT = "###### ";
    private static final String INDICATION_PREFIX_HTML
            = "<center><label style=\"font-family:Arial;font-weight:bold;font-size:10pt\">";

    private static final String INDICATION_POSTFIX_PLAINTEXT = "\r\n\r\n";
    private static final String INDICATION_POSTFIX_HTML = "</label></center>";

    private static final String DELIMITER_HTML = "<br>";
    private static final String DELIMITER_PLAINTEXT = "\r\n";

    public static final String HTML_INDICATOR = "<!--html-->";

    public static boolean isHTML(String text) {
        return text.indexOf(HTML_INDICATOR) != -1;
    }

    public HtmlEditFrame(QMemoModel model) {
        super();

        this.model = model;

        memoType = model.getMeta().getMemoType();

        initEditor();

        lockedHTML = new HTML();
        rsp = new ResizableScrollPanel();
        rsp.add(lockedHTML);
        rsp.setVisible(false);
        rsp.setStyleName("html_viewer");

        add(editor);
        add(rsp);
    }

    public String getHTML() {
        return editor.getHTML();
    }

    public boolean isShowFrame() {
        return editor.getEditorWYSIWYG().isShowFrame();
    }

    public void load() {
        setEnabled(true);

        if(!model.getMeta().isInline()) {
            setOffsetHeight(DEFAULT_HEIGHT);
        }
        setOffsetWidth(DEFAULT_WIDTH);

        setupLockedPanelVisibility();

        editor.setMemoType(memoType);
        fireTextLoad();
    }

    public void setupLockedPanelVisibility() {
        rsp.setVisible(memoType == MemoFieldMeta.PREPPEND_TYPE
                || memoType == MemoFieldMeta.APPEND_TYPE);
    }

    public void setHasRecords(boolean hasRecords) {
        editor.setHasRecords(hasRecords);
    }

    public void setupEditor(String text) {
        if(text.equals("")) {
            toggleView(true);
        } else {
            toggleView(isHTML(text));
        }
        setupLockedPanelVisibility();
        setHasRecords(!text.trim().equals(""));
    }

    public void toggleView(boolean toHtml) {
        if(toHtml) {
            if(!editor.getEditorWYSIWYG().isShowFrame()) {
                editor.getEditorWYSIWYG().toggleView();
            }
        } else {
            if(editor.getEditorWYSIWYG().isShowFrame()) {
                editor.getEditorWYSIWYG().toggleView();
            }
        }
    }

    private void toggleView(String text) {
        if(!StringUtil.nullToEmpty(text).equals("")) {
            if(isHTML(text)) {
                toggleView(true);
            } else {
                toggleView(false);
            }
        } else {
            toggleView(true);
        }
    }

    private void setEditorFrame() {
        String text = model.getData().getText();
        editor.setHTML("");
        toggleView(text);
    }

    public void unload() {
        setEnabled(false);
    }

    public boolean isEnabled() {
        return isEnabled;
    }

    public void setEnabled(boolean enabled) {
        this.isEnabled = enabled;
    }

    private void initEditor() {
        editor = new Editor();
        setLoaded(false);
        editor.addLoadListener(new LoadListener() {
            public void onLoad(Widget sender) {
                setLoaded(true);
                setEditorFrame();
                fireTextLoad();
            }

            public void onError(Widget sender) {
            }
        });
        editor.getToolbarEventSource().addEventListener(this);
        editor.getEditorEventSource().addEventListener(this);
    }

    public String getText() {
        return getText(StringUtil.nullToEmpty(getLockedText()));
    }

    public String getText(String textToConcatinate) {
        if(isLoaded()) {
            String text = "";
            switch(memoType) {
                case MemoFieldMeta.PREPPEND_TYPE:
                    text = getHTML();
                    if(!text.equals("")) {
                        text = getUserText() + text + getTextDelimiter()
                                + getTextDelimiter();
                        if(textToConcatinate != null) {
                            text += textToConcatinate;
                        }
                    } else {
                        text = textToConcatinate != null ? textToConcatinate:"";
                    }
                    break;
                case MemoFieldMeta.APPEND_TYPE:
                    if(!getHTML().equals("")) {
                        text = textToConcatinate != null ? textToConcatinate:"";
                        if(!text.equals("")) {
                            text += getTextDelimiter();
                        }
                        text += getUserText() + getHTML() + getTextDelimiter();
                    } else {
                        text = textToConcatinate != null ? textToConcatinate:"";
                    }
                    break;
                case MemoFieldMeta.EDIT_TYPE:
                    text = getHTML();
                    break;
            }
            return text;
        } else {
            return getTextToLoad();
        }
    }

    private String getUserText() {
        String res = getIndicationPrefix()
                + Application.getUserProfile().getFullName() + getTime()
                + getIndicationPostfix();
        return res;
    }

    private String addLeadingZero(int n) {
        return n > 9 ? Integer.toString(n):"0" + n;
    }

    private static final String[] MONTHS = {
            "Jan",
            "Feb",
            "Mar",
            "Apr",
            "May",
            "Jun",
            "Jul",
            "Aug",
            "Sep",
            "Oct",
            "Nov",
            "Dec"
    };

    private String getTime() {
        //TODO format on server side via RPC request
        Date d = DateHelper.getUserDate();
        String res = ", " + addLeadingZero(d.getDate()) + " "
                + MONTHS[d.getMonth()] + " " + (d.getYear() + 1900) + " "
                + addLeadingZero(d.getHours()) + ":" + addLeadingZero(
                d.getMinutes());
        return res;
    }

    public String getLockedText() {
        return isLockedTextHTML ? lockedHTML.getHTML()
                :lockedText;//lockedText.getText();
    }

    public void setLockedText(String text) {
        if(isLockedTextHTML) {
            lockedHTML.setHTML(text);
        } else {
            setLockedTxt(text);
        }
    }

    private void setLockedTxt(String text) {
        lockedText = text;
        lockedHTML.setHTML(addPre(text));
    }

    private String addPre(String text) {
        return "<pre>" + text + "</pre>";
    }

    private String getDelimiter() {
        if(editor.getEditorWYSIWYG().isShowFrame()) {
            return DELIMITER_HTML;
        } else {
            return getTextDelimiter();
        }
    }

    private String getTextDelimiter() {
        if(editor.getEditorWYSIWYG().isShowFrame()) {
            return "";
        } else {
            return DELIMITER_PLAINTEXT;
        }
    }

    private String getIndicationPrefix() {
        if(editor.getEditorWYSIWYG().isShowFrame()) {
            return INDICATION_PREFIX_HTML;
        } else {
            return INDICATION_PREFIX_PLAINTEXT;
        }
    }

    private String getIndicationPostfix() {
        if(editor.getEditorWYSIWYG().isShowFrame()) {
            return INDICATION_POSTFIX_HTML;
        } else {
            return INDICATION_POSTFIX_PLAINTEXT;
        }
    }

    public void setText(String str) {
        setTextToLoad(str);
        fireTextLoad();
    }

    synchronized private void fireTextLoad() {
        if(isLoaded() && isEnabled()) {
            String text = getTextToLoad();
            if(text != null) {
                if(!text.equals("")) {
                    if(memoType == MemoFieldMeta.EDIT_TYPE) {
                        editor.setHTML(text);
                    } else {
                        notEditStyle(text);
                    }
                } else {
                    lockedHTML.setText("");
                    setLockedTxt("");
                    editor.setHTML("");
                }
                setTextToLoad(null);
            }
        }
    }

    private void notEditStyle(String text) {
        isLockedTextHTML = isHTML(text);
        if(isLockedTextHTML) {
            lockedHTML.setHTML(text);
        } else {
            setLockedTxt(text);
        }
    }

    synchronized private boolean isLoaded() {
        return isEditorLoaded;
    }

    synchronized public void setLoaded(boolean loaded) {
        isEditorLoaded = loaded;
    }

    private String getTextToLoad() {
        return textToLoad;
    }

    private void setTextToLoad(String str) {
        textToLoad = str;
    }

    public void onEvent(Event event, Widget sender) {
        if(event == EditorToolbar.Events.PANEL_CHANGE) {
            setupLockedPanelVisibility();
        } else if(OkayCancelPopup.Events.CANCEL == event) {
            setTextToLoad(getHTML());
            unload();
            fireEvent(event, sender);
        } else {
            fireEvent(event, sender);
        }
    }

    public void addEventListener(EventListener eventListener) {
        this.eventListener = eventListener;
    }

    public void fireEvent(Event ev, Widget sender) {
        if(null != eventListener) {
            eventListener.onEvent(ev, sender);
        }
    }

    public void setOffsetHeight(int height) {
        if(memoType == MemoFieldMeta.EDIT_TYPE) {
            editor.setHeight(height + "px");
        } else {
            String half = height / 2 + "px";
            rsp.setHeight(half);
            editor.setHeight(half);
        }
    }

    public int getOffsetHeight() {
        if(memoType == MemoFieldMeta.EDIT_TYPE) {
            return editor.getOffsetHeight();
        }
        return editor.getOffsetHeight() + lockedHTML.getOffsetHeight();
    }

    public void setOffsetWidth(int width) {
        if(width >= MIN_WIDTH) {
            editor.setWidth(width + "px");
        } else {
            editor.setWidth(MIN_WIDTH + "px");
        }
        if(memoType != MemoFieldMeta.EDIT_TYPE) {
            if(width >= MIN_WIDTH) {
                rsp.setWidth(width + "px");
            } else {
                rsp.setWidth(MIN_WIDTH + "px");
            }
        }
    }

    public void resetEditor() {
        if(memoType == MemoFieldMeta.EDIT_TYPE) {
        } else {
            editor.setHTML("");
        }
    }

    public void setAddLinkAsAttachment(boolean isAddLinkAsAttachment) {
        editor.getEditorToolbar().setAddLinkAsAttachment(isAddLinkAsAttachment);
    }

    public void setImageAttachmentAction(String string) {
        editor.getEditorToolbar().setImageAttachmentAction(string);
    }
}
