/*
 * Copyright 2006 Pavel Jbanov.
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * 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.jpavel.gwt.wysiwyg.client;

import com.google.gwt.user.client.DOM;
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.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasAlignment;
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.PopupListener;
import com.google.gwt.user.client.ui.PopupPanel;
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.events.ImageAttached;
import com.queplix.core.client.app.vo.MemoFieldMeta;
import com.queplix.core.client.common.event.Event;
import com.queplix.core.client.common.event.EventListener;
import com.queplix.core.client.common.event.EventSource;
import com.queplix.core.client.common.ui.DialogHelper;
import com.queplix.core.client.common.ui.OkayCancelPopup;
import com.queplix.core.client.common.ui.upload.QFileUpload;
import com.queplix.core.client.common.ui.upload.QFileUploadListener;
import com.queplix.core.client.i18n.I18N;

public class EditorToolbar extends Composite {
    private static final String CONFIRMATION_MESSAGE = I18N.getMessages().memoHTMLtoPlaintextConfirmation();
    
    final private Editor editor;
    
    private FlowPanel fullToolbar;
    private FlowPanel shortToolbar;
    private VerticalPanel topContainer;
    private EditorColorPicker fgPicker;
    private EditorColorPicker bgPicker;
    
    private OkayCancelPopup fileUploadPopup;
    private QFileUpload fileUpload;
    
    private int memoType;
    private boolean hasRecords;
    
    private OkayCancelPopup insertLinkPopup;
    private Widget insertLinkPanel;
    
    private boolean isAddLinkAsAttachment;
    private String imageAttachmentAction;
    
    // -------------------- public events ------------------------
    public static interface Events {
        Event PANEL_CHANGE = new Event();
        Event IMAGE_ATTACHED = new Event();
    }
    
    private EventSource eventSource = new EventSource(this);
    
    public EventSource getEventSource() {
        return eventSource;
    }
    // ----------------- end of public events --------------------
    
    private void initInsertLinkPanel() {
        if (insertLinkPopup != null) {
            return;
        }
        
        insertLinkPopup = new OkayCancelPopup("Insert Link");
        
        insertLinkPanel = new VerticalPanel();
        HorizontalPanel hp = new HorizontalPanel();
        Label nameLabel = new Label("Name");
        nameLabel.setWidth(35 + "px");
        hp.add(nameLabel);
        hp.setCellVerticalAlignment(nameLabel, HasVerticalAlignment.ALIGN_MIDDLE);
        final TextBox name = new TextBox();
        name.setWidth(200 + "px");
        hp.add(name);
        HorizontalPanel hp2 = new HorizontalPanel();
        Label urlLabel = new Label("URL");
        urlLabel.setWidth(35 + "px");
        hp2.add(urlLabel);
        hp2.setCellVerticalAlignment(urlLabel, HasVerticalAlignment.ALIGN_MIDDLE);
        final TextBox url = new TextBox();
        url.setWidth(200 + "px");
        hp2.add(url);
        
        ((VerticalPanel) insertLinkPanel).add(hp);
        ((VerticalPanel) insertLinkPanel).add(hp2);
        
        insertLinkPopup.setWidget(insertLinkPanel);
        insertLinkPopup.getEventSource().addEventListener(new EventListener() {
            public void onEvent(Event event, Widget sender) {
                if (event == OkayCancelPopup.Events.OK) {
                    String linkName = name.getText();
                    String link = url.getText();
                    if (! link.startsWith("http://")) {
                        link = "http://" + link;
                    }
                    insertLinkPopup.hide();
                    // pasteHTML does work not for FF when IFRAME is in popup; use appendHTML instead:
                    link = "<a href='" + link + "' target='_blank'>" + linkName + "</a>";
                    if (!EditorUtils.isGecko()) {
                        editor.pasteHTML(link);
                    } else {
                        editor.appendHTML(link);
                    }
                } else if (event == OkayCancelPopup.Events.CANCEL) {
                    insertLinkPopup.hide();
                }
            }
        });
    }
    
    private void initFileUpload() {
        if (fileUploadPopup != null) {
            return;
        }
        
        if (imageAttachmentAction == null) {
            imageAttachmentAction = QFileUpload.DEFAULT_ACTION;
        }
        fileUpload = new QFileUpload(imageAttachmentAction, false);
        fileUpload.addQFileUploadListener(new QFileUploadListener() {
            public void onFileUploaded(Widget sender, String fileName) {
                String url = createURL(fileName);
                String attachmentSrc = "";
                
                if (isAddLinkAsAttachment) {
                    String fname = getFileName(fileUpload.getFileUploadName());
                    attachmentSrc = "cid:" + fname;
                    Events.IMAGE_ATTACHED.setData(new ImageAttached(fileName, fname));
                    eventSource.fireEvent(Events.IMAGE_ATTACHED);
                } else {
                    attachmentSrc = "notAttachment";
                }
                String html = " <img src=\"" + url + "\" attachment=\"" + attachmentSrc + "\"/>";
                
                // pasteHTML does work not for FF when IFRAME is in popup; use appendHTML instead:
                if (!EditorUtils.isGecko()) {
                    editor.pasteHTML(html);
                } else {
                    editor.appendHTML(html);
                }
                fileUploadPopup.hide();
            }
        });
        fileUploadPopup = new OkayCancelPopup("Insert Image", true);
        fileUploadPopup.getEventSource().addEventListener(new EventListener() {
            public void onEvent(Event event, Widget sender) {
                if (event == OkayCancelPopup.Events.OK) {
                    fileUpload.submitUpload();
                } else if (event == OkayCancelPopup.Events.CANCEL) {
                    fileUploadPopup.hide();
                }
            }
        });
        fileUploadPopup.setWidget(fileUpload);
    }
    
    private String getFileName(String text) {
        int index = -1;
        if ( (index = text.lastIndexOf('/')) == -1) {
            index = text.lastIndexOf('\\');
        }
        return index == -1 ? text : text.substring(index + 1);
    }
    
    private String createURL(String fileName) {
        return isAddLinkAsAttachment ? "../attachmentUpload/getTemp?id=" + fileName : "../fileUpload/get?filepath=" + fileName;
    }
    
    public EditorToolbar(Editor _editor) {
        topContainer = new VerticalPanel();
        topContainer.setStyleName("Editor-Toolbar");
        topContainer.setWidth("100%");
        
        this.editor = _editor;
        
        fullToolbar = new FlowPanel();
        
        shortToolbar = new FlowPanel();
        
        EditorToolbarButton source = new EditorToolbarButton(EditorToolbarButton.BUTTON_PLAIN_TEXT);
        source.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                if(memoType == MemoFieldMeta.EDIT_TYPE ||
                        (memoType != MemoFieldMeta.EDIT_TYPE && !hasRecords)) {
                    if (!editor.getEditorWYSIWYG().getHTML().trim().equals("") &&
                            DialogHelper.showModalQuestionDialog(CONFIRMATION_MESSAGE) == DialogHelper.NO) {
                        return;
                    }
                    editor.getEditorWYSIWYG().toggleView();
                    if(memoType != MemoFieldMeta.EDIT_TYPE) {
                        eventSource.fireEvent(Events.PANEL_CHANGE);
                    }
                }
            }
        });
        
        EditorToolbarButton removeFormat = new SimpleCommandButton(EditorToolbarButton.BUTTON_DELETE, "RemoveFormat");
        
        EditorToolbarButton undo = new SimpleCommandButton(EditorToolbarButton.BUTTON_UNDO, "Undo");
        EditorToolbarButton redo = new SimpleCommandButton(EditorToolbarButton.BUTTON_REDO, "Redo");
        
        EditorToolbarButton bold = new SimpleCommandButton(EditorToolbarButton.BUTTON_BOLD, "Bold");
        EditorToolbarButton italic = new SimpleCommandButton(EditorToolbarButton.BUTTON_ITALIC, "Italic");
        EditorToolbarButton underlined = new SimpleCommandButton(EditorToolbarButton.BUTTON_UNDERLINE, "Underline");
        
        EditorToolbarButton subscript = new SimpleCommandButton(EditorToolbarButton.BUTTON_SUBSCRIPT, "Subscript");
        EditorToolbarButton superscript = new SimpleCommandButton(EditorToolbarButton.BUTTON_SUPERSCRIPT, "Superscript");
        
        EditorToolbarButton justifyLeft = new SimpleCommandButton(EditorToolbarButton.BUTTON_ALIGNLEFT, "JustifyLeft");
        EditorToolbarButton justifyCenter = new SimpleCommandButton(EditorToolbarButton.BUTTON_ALIGNCENTER, "JustifyCenter");
        EditorToolbarButton justifyRight = new SimpleCommandButton(EditorToolbarButton.BUTTON_ALIGNRIGHT, "JustifyRight");
        EditorToolbarButton justifyJustify = new SimpleCommandButton(EditorToolbarButton.BUTTON_ALIGNJUSTIFY, "JustifyFull");
        
        EditorToolbarButton ol = new SimpleCommandButton(EditorToolbarButton.BUTTON_OL, "InsertOrderedList");
        EditorToolbarButton ul = new SimpleCommandButton(EditorToolbarButton.BUTTON_UL, "InsertUnorderedList");
        
        EditorToolbarButton link = new EditorToolbarButton(EditorToolbarButton.BUTTON_LINK);
        link.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                if (!editor.getEditorWYSIWYG().isFrameFocused()) {
                    EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
                }
                EditorUtils.saveSelection(editor.getEditorWYSIWYG().getFrame().getElement());
                initInsertLinkPanel();
                insertLinkPopup.show();
            }
        });
        
        EditorToolbarButton unlink = new SimpleCommandButton(EditorToolbarButton.BUTTON_UNLINK, "UnLink");
        final EditorToolbarButton image = new EditorToolbarButton(EditorToolbarButton.BUTTON_IMAGE);
        image.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                if (!editor.getEditorWYSIWYG().isFrameFocused()) {
                    EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
                }
                EditorUtils.saveSelection(editor.getEditorWYSIWYG().getFrame().getElement());
                initFileUpload();
                fileUploadPopup.show();
            }
        });
        
        EditorToolbarButton foreColor = new EditorToolbarButton(EditorToolbarButton.BUTTON_TEXTCOLOR);
        foreColor.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                EditorUtils.saveSelection(editor.getEditorWYSIWYG().getFrame().getElement());
                initFgPicker();
                fgPicker.show();
                fgPicker.setPopupPosition(editor.getAbsoluteLeft() + 50, editor.getAbsoluteTop() + 50);
            }
        });
        
        EditorToolbarButton bgColor = new EditorToolbarButton(EditorToolbarButton.BUTTON_TEXTBACKGROUNDCOLOR);
        bgColor.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                EditorUtils.saveSelection(editor.getEditorWYSIWYG().getFrame().getElement());
                initBgPicker();
                bgPicker.show();
                bgPicker.setPopupPosition(editor.getAbsoluteLeft() + 50, editor.getAbsoluteTop() + 50);
            }
        });
        
        EditorToolbarSelect styles = new EditorToolbarSelect();
        styles.addItem("Style", "");
        String[][] formats = EditorUtils.getSupportedFormats();
        for (int i = 0; i < formats.length; i++) {
            styles.addItem(formats[i][0], formats[i][1]);
        }
        
        styles.addChangeListener(new ChangeListener() {
            public void onChange(Widget sender) {
                ListBox subj = ((ListBox) sender);
                String value = subj.getValue(subj.getSelectedIndex());
                subj.setSelectedIndex(0);
                EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
                editor.execCommand("FormatBlock", false, value);
            }
        });
        
        EditorToolbarSelect fontSizes = new EditorToolbarSelect();
        fontSizes.addItem("Size", "");
        for (int i = 1; i < 8; i++) {
            fontSizes.addItem("Size " + i, "" + i);
        }
        
        fontSizes.addChangeListener(new ChangeListener() {
            public void onChange(Widget sender) {
                ListBox subj = ((ListBox) sender);
                String value = subj.getValue(subj.getSelectedIndex());
                subj.setSelectedIndex(0);
                editor.execCommand("FontSize", false, value);
                EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
            }
        });
        
        fullToolbar.add(source);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(removeFormat);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(undo);
        fullToolbar.add(redo);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(bold);
        fullToolbar.add(italic);
        fullToolbar.add(underlined);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(subscript);
        fullToolbar.add(superscript);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(justifyLeft);
        fullToolbar.add(justifyCenter);
        fullToolbar.add(justifyRight);
        fullToolbar.add(justifyJustify);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(ol);
        fullToolbar.add(ul);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(link);
        fullToolbar.add(unlink);
        fullToolbar.add(image);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(foreColor);
        fullToolbar.add(bgColor);
        
        fullToolbar.add(EditorToolbarButton.getSpacer());
        
        fullToolbar.add(styles);
        fullToolbar.add(fontSizes);
        
        EditorToolbarButton source2 = new EditorToolbarButton(EditorToolbarButton.BUTTON_NEW2);
        source2.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                if(memoType == MemoFieldMeta.EDIT_TYPE ||
                        (memoType != MemoFieldMeta.EDIT_TYPE && !hasRecords)) {
                    editor.getEditorWYSIWYG().toggleView();
                    if(memoType != MemoFieldMeta.EDIT_TYPE) {
                        eventSource.fireEvent(Events.PANEL_CHANGE);
                    }
                }
            }
        });
        
        shortToolbar.add(source2);
        
        topContainer.add(fullToolbar);
        topContainer.add(shortToolbar);
        
        fullToolbar.setVisible(true);
        shortToolbar.setVisible(false);
        
        initWidget(topContainer);
    }
    
    private void initFgPicker() {
        if(fgPicker != null) {
            return;
        }
        fgPicker = new EditorColorPicker("Select Text Color");
        fgPicker.addSelectListener(new EditorColorSelectListener() {
            public void colorSelected(String rgb) {
                EditorUtils.restoreSelection(editor.getEditorWYSIWYG().getFrame().getElement());
                editor.execCommand("ForeColor", false, rgb);
                EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
            }
        });
    }
    
    private void initBgPicker() {
        if(bgPicker != null) {
            return;
        }
        bgPicker = new EditorColorPicker("Select Background Color");
        bgPicker.addSelectListener(new EditorColorSelectListener() {
            public void colorSelected(String rgb) {
                EditorUtils.restoreSelection(editor.getEditorWYSIWYG().getFrame().getElement());
                editor.execCommand(EditorUtils.isIE()? "backcolor" : "hilitecolor", false, rgb);
                EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
            }
        });
    }
    
    private class SimpleCommandButton extends EditorToolbarButton {
        public SimpleCommandButton(String buttonId, final String command) {
            this(buttonId, command, false, null);
        }
        
        public SimpleCommandButton(String buttonId, final String command, final boolean ui, String value) {
            super(buttonId);
            
            this.addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    //					EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
                    EditorUtils.execCommand(editor.getEditorWYSIWYG().getFrame().getElement(), command, ui, null);
                }
            });
        }
    }
    
    public class SimplePromptPannel extends EditorToolbarButton {
        public SimplePromptPannel(String buttonId, final String command, final String question) {
            super(buttonId);
            
            this.addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    String value = EditorUtils.prompt(question);
                    if (value != null) {
                        EditorUtils.doFocus(editor.getEditorWYSIWYG().getFrame().getElement());
                        editor.execCommand(command, false, value);
                    }
                }
            });
        }
    }
    
    public void setWidth(String width) {
        topContainer.setWidth(width);
    }
    
    public String getWidth() {
        return DOM.getStyleAttribute(topContainer.getElement(), "width");
    }
    
    public void switchToSmall() {
        fullToolbar.setVisible(false);
        shortToolbar.setVisible(true);
    }
    
    public void switchToFull() {
        fullToolbar.setVisible(true);
        shortToolbar.setVisible(false);
    }
    
    public void setMemoType(int memoType) {
        this.memoType = memoType;
    }
    
    public void setHasRecords(boolean hasRecords) {
        this.hasRecords = hasRecords;
    }

    public void setAddLinkAsAttachment(boolean isAddLinkAsAttachment) {
        this.isAddLinkAsAttachment = isAddLinkAsAttachment;
    }
    
    public void setImageAttachmentAction(String string) {
        if (fileUpload != null) {
            fileUpload.setAction(string);
        }
        imageAttachmentAction = string;
    }
}
