/*
 * Copyright (c) 2002-2008 Pixware. 
 *
 * Author: Hussein Shafie
 *
 * This file is part of the XMLmind XML Editor project.
 * For conditions of distribution and use, see the accompanying legal.txt file.
 */

import java.io.File;

import java.net.URL;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuBar;

import com.xmlmind.util.ThrowableUtil;

import com.xmlmind.xml.doc.Document;

import com.xmlmind.guiutil.Alert;

import com.xmlmind.xmledit.edit.SendDocumentEvent;
import com.xmlmind.xmledit.edit.StyleSheetInfo;
import static com.xmlmind.xmledit.edit.Constants.STYLE_SHEET_INFO_PROPERTY;

import com.xmlmind.xmledit.view.DocumentPane;
import com.xmlmind.xmledit.view.DocumentView;

import com.xmlmind.xmledit.stylesheet.StyleSheet;
import com.xmlmind.xmledit.stylesheet.StyleSheetLoader;

import com.xmlmind.xmledit.styledview.StyledDocumentPane;
import com.xmlmind.xmledit.styledview.StyledViewFactory;

public class StyledEditor extends SimpleEditor {
    // -----------------------------------------------------------------------
    // Menu items
    // -----------------------------------------------------------------------
    protected static final int STYLE_MENU = 4;

    protected static final int NO_STYLE_ITEM = 0;

    // -----------------------------------------------------------------------
    // Internal state
    // -----------------------------------------------------------------------

    protected StyleSheetInfo[] styleSheets = null;

    // -----------------------------------------------------------------------
    // Main
    // -----------------------------------------------------------------------

    public static void main(String[] args) {
        StyledEditor app = new StyledEditor();
        app.run(args);
    }

    // -----------------------------------------------------------------------
    // Initialization
    // -----------------------------------------------------------------------

    protected DocumentPane createDocumentPane() {
        return new StyledDocumentPane();
    }

    protected void configureMenuBar(JMenuBar menuBar) {
        super.configureMenuBar(menuBar);

        JMenu menu = new JMenu("Style");

        JMenuItem item = new JMenuItem("No Style");
        item.setEnabled(false);
        item.setActionCommand("setStyle-1");
        item.addActionListener(this);
        menu.add(item);

        menuBar.add(menu);
    }

    public void actionPerformed(ActionEvent event) {
        String command = event.getActionCommand();

        if (command.startsWith("setStyle")) {
            int index = Integer.MIN_VALUE;
            try {
                index = Integer.parseInt(command.substring(8));
            } catch (NumberFormatException cannotHappen) {}

            int styleCount = (styleSheets == null)? 0 : styleSheets.length;
            if (index >= -1 && index < styleCount)
                setStyle(index);
        } else {
            super.actionPerformed(event);
        }
    }

    // -----------------------------------------------------------------------
    // Commands
    // -----------------------------------------------------------------------

    // -----------------------------------
    // Open
    // -----------------------------------

    protected Document loadDocument(File file) {
        Document doc = super.loadDocument(file);

        if (doc != null) {
            StyleSheetInfo[] prop = StyleSheetInfo.loadStyleSheetPI(doc);
            if (prop != null)
                doc.putProperty(STYLE_SHEET_INFO_PROPERTY, prop);
        }

        return doc;
    }

    protected void uninstallDocument(Document doc) {
        super.uninstallDocument(doc);

        uninstallStyleSheets();
        setStyle(-1);
    }

    protected void uninstallStyleSheets() {
        styleSheets = null;
        updateStyleMenu();
        getMenuItem(STYLE_MENU, NO_STYLE_ITEM).setEnabled(false);
    }

    protected void installDocument(Document doc) {
        super.installDocument(doc);

        if (installStyleSheets(doc)) 
            setStyle(0);
    }

    protected boolean installStyleSheets(Document doc) {
        StyleSheetInfo[] prop = 
            (StyleSheetInfo[]) doc.getProperty(STYLE_SHEET_INFO_PROPERTY);

        StyleSheetInfo[] list = null;
        int count = 0;
        int firstNonAlternate = -1;

        if (prop != null) {
            list = new StyleSheetInfo[prop.length];

            for (int i = 0; i < prop.length; ++i) {
                StyleSheetInfo info = prop[i];

                if (info.type.equals("text/css") &&
                    (info.media == null || info.media.equals("screen"))) {
                    if (!info.alternate && firstNonAlternate < 0)
                        firstNonAlternate = count;
                    list[count++] = info;
                }
            }
        }
        if (count == 0)
            return false;

        if (count > 10)
            count = 10;
        if (count == list.length) {
            styleSheets = list;
        } else {
            styleSheets = new StyleSheetInfo[count];
            System.arraycopy(list, 0, styleSheets, 0, count);
        }

        if (firstNonAlternate < 0)
            firstNonAlternate = 0;
        if (firstNonAlternate != 0) {
            StyleSheetInfo swap = list[firstNonAlternate];
            if (firstNonAlternate < styleSheets.length)
                styleSheets[firstNonAlternate] = styleSheets[0];
            styleSheets[0] = swap;
        }

        updateStyleMenu();
        getMenuItem(STYLE_MENU, NO_STYLE_ITEM).setEnabled(true);

        return true;
    }

    protected void updateStyleMenu() {
        JMenu menu = menuBar.getMenu(STYLE_MENU);
        // [0] No Style, [1] -
        for (int i = menu.getItemCount() - 1; i >= 1; --i) 
            menu.remove(i);

        if (styleSheets != null) {
            menu.addSeparator();

            for (int i = 0; i < styleSheets.length; ++i) {
                StyleSheetInfo info = styleSheets[i];

                JMenuItem item = new JMenuItem(info.getLabel());
                item.setActionCommand("setStyle" + i);
                item.addActionListener(this);
                menu.add(item);
            }
        }
    }

    // -----------------------------------
    // SetStyle
    // -----------------------------------

    protected void setStyle(int index) {
        StyleSheet styleSheet = null;

        if (index >= 0) {
            StyleSheetInfo info = styleSheets[index];

            styleSheet = loadStyleSheet(info.url);
            if (styleSheet == null) {
                JMenuItem item = getMenuItem(STYLE_MENU, 2+index);
                item.setEnabled(false);
            }
        }

        StyledViewFactory viewFactory = 
            (StyledViewFactory) docView.getViewFactory();
        if (styleSheet != null || viewFactory.getStyleSheet() != null)
            setStyleSheet(viewFactory, styleSheet);
    }

    protected StyleSheet loadStyleSheet(URL url) {
        StyleSheetLoader loader = new StyleSheetLoader();
        StyleSheet styleSheet = null;
        String error = null;

        try {
            styleSheet = loader.load(url, /*media*/ null);
        } catch (Exception e) {
            error = ThrowableUtil.reason(e);
        }

        if (styleSheet == null) {
            Alert.showError(frame, 
                           "Cannot load CSS style sheet '" + url + "':\n" + 
                            error);
        } else {
            StyleSheetLoader.Warning[] warnings = loader.getWarnings();

            if (warnings.length > 0) {
                StringBuffer messages = new StringBuffer();

                for (int j = 0; j < warnings.length; ++j) {
                    StyleSheetLoader.Warning warn = warnings[j];

                    messages.append(warn.url);
                    messages.append(':');
                    messages.append(warn.lineNumber);
                    messages.append(':');
                    messages.append(warn.columnNumber);
                    messages.append(": ");
                    messages.append(warn.message);
                    messages.append("\n\n");
                }

                Alert.showWarning(frame, 
                                  "CSS style sheet '" + url + "' has errors:",
                                  messages.toString(), true, 10, 40);
            }
        }

        return styleSheet;
    }

    protected void setStyleSheet(StyledViewFactory viewFactory, 
                                 StyleSheet styleSheet) {
        Document doc = viewFactory.getDocumentView().getDocument();
        SendDocumentEvent.commitChanges(doc);

        viewFactory.setStyleSheet(styleSheet);
    }
}
