/*
 * 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.modules.config.actions;

import com.queplix.core.error.GenericSystemException;
import com.queplix.core.modules.config.ejb.FocusConfigManager;
import com.queplix.core.modules.config.ejb.FocusConfigManagerHome;
import com.queplix.core.modules.config.jxb.Button;
import com.queplix.core.modules.config.jxb.Col;
import com.queplix.core.modules.config.jxb.Filter;
import com.queplix.core.modules.config.jxb.Focus;
import com.queplix.core.modules.config.jxb.Form;
import com.queplix.core.modules.config.jxb.Header;
import com.queplix.core.modules.config.jxb.Htmlelement;
import com.queplix.core.modules.config.jxb.Htmlelements;
import com.queplix.core.modules.config.jxb.Row;
import com.queplix.core.modules.config.jxb.SubFocus;
import com.queplix.core.modules.config.jxb.Tab;
import com.queplix.core.modules.config.utils.EntityHelper;
import com.queplix.core.modules.services.Action;
import com.queplix.core.utils.JNDINames;
import com.queplix.core.utils.xml.XMLBinding;
import com.queplix.core.utils.xml.XMLFactory;
import com.queplix.core.utils.xml.XMLWrapper;
import org.w3c.dom.Document;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>Action wich parses config XML files and fills Form EJBs</p>
 *
 * @author [ALB] Baranov Andrey
 * @author Sergey Kozmin
 */

public class FormInstallationAction
        extends Action {

    // constants
    private static final String CONFIG_FILES_EXTENSION = "xml";

    // variables
    private XMLWrapper xmlWrapper = XMLFactory.getXMLWrapper();
    private XMLBinding xmlBind = XMLFactory.getXMLBinding();

    public Serializable perform() {
        String[] focusdir = (String[]) getContext().getParameter("focusdir");
        if(focusdir == null) {
            throw new NullPointerException("Parameter focus dir is NULL");
        }

        try {
            // Do process
            INFO("PROCESS STARTED...");
            long time = System.currentTimeMillis();

            List<Focus> focusList = parseFocusesFromDirs(focusdir);
            INFO("parse focuse config - ok");
            buildFocusList(focusList);
            INFO("build focus - ok");
            deployFocusConfigs(focusList);
            INFO("deploy focus configs - ok");

            // Ok.
            INFO("Process last(s): "
                    + (System.currentTimeMillis() - time) / 1000);
            INFO("PROCESS DONE !!!");

        } catch (GenericSystemException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new GenericSystemException(
                    "Unknown exception: " + ex.getMessage(), ex);
        }
        return null;
    }

// --------------------- PRIVATE METHODS -------------------

    /**
     * Parse focus xml configs and fill the table of Focus objects
     *
     * @param focusDirFiles files of the focuses dirs.
     * @return merged focuses list.
     */
    private List<Focus> parseFocusesFromDirs(String[] focusDirFiles) {
        List<Focus> ret = new LinkedList<Focus>();
        LinkedHashMap<String, Focus> unicFocuses
                = new LinkedHashMap<String, Focus>();
        for(String focusDir : focusDirFiles) {
            List<Focus> focuses = parseFocusesFromDir(focusDir);
            for(Focus focus : focuses) {
                unicFocuses.put(focus.getName(), focus);
            }
        }
        for(Focus focus : unicFocuses.values()) {
            INFO("Add focus :" + focus.getName());
            ret.add(focus);
        }
        return ret;
    }

    private List<Focus> parseFocusesFromDir(String focusDir) {
        List<Focus> focusList = new ArrayList<Focus>();
        File focusDirFile = new File(focusDir);
        if(!focusDirFile.exists() || !focusDirFile.isDirectory()) {
            ERROR("Bad form config dir: " + focusDirFile.getAbsolutePath());
        } else {
            // get list of files
            File[] files = focusDirFile.listFiles(new FilenameFilter() {
                public boolean accept(File dir, String name) {
                    String ext = CONFIG_FILES_EXTENSION;
                    return name.substring(name.length() - ext.length()).equals(
                            ext);
                }
            });

            try {
                // cycle read focus config XML files
                for(File file : files) {
                    INFO("  read from " + file.getCanonicalPath());

                    // build Focus object
                    Document document = xmlWrapper.getDocument(file, false);
                    Focus focus = (Focus) xmlBind.xmlToJava(Focus.class,
                            document);
                    focusList.add(focus);
                }

            } catch (IOException ex) {
                ERROR(ex);
                throw new GenericSystemException(
                        "IO exception. Can't process parsing focuses: " + ex
                                .getMessage(), ex);
            }
        }
        return focusList;
    }

    /**
     * Build list of Focus objects and fill additional attributes
     *
     * @param focusList list of parsed focuses
     */
    private void buildFocusList(List<Focus> focusList) {

        // fill name attributes
        int sizei = focusList.size();
        for(int i = 0; i < sizei; i++) {
            Focus focus = focusList.get(i);
            String focusName = focus.getName();
            focus.setOrder(i);

            int sizem = focus.getSubFocusCount();
            for(int m = 0; m < sizem; m++) {
                SubFocus subFocus = focus.getSubFocus(m);
                String subFocusName = EntityHelper.getSubFocusFullName(
                        focusName, subFocus);
                subFocus.setName(subFocusName);
                subFocus.setFocus(focusName);
                subFocus.setOrder(m);

                int sizej = subFocus.getTabCount();
                for(int j = 0; j < sizej; j++) {
                    Tab tab = subFocus.getTab(j);
                    String tabName = EntityHelper.getTabFullName(subFocusName,
                            tab);
                    tab.setName(tabName);
                    tab.setSubFocus(subFocusName);
                    tab.setOrder(j);

                    int sizek = tab.getFormCount();
                    for(int k = 0; k < sizek; k++) {
                        Form form = tab.getForm(k);
                        String formName = EntityHelper.getFormFullName(tabName,
                                form);
                        form.setName(formName);
                        form.setTab(tabName);
                        form.setOrder(k);
                        form.setDefaultactions(
                                EntityHelper.FormHelper.getFormDefaultActions(
                                        form));
                        //fill form buttons
                        Button[] buttons = EntityHelper.FormHelper
                                .getFormButtons(form);
                        if(buttons.length != 0) {
                            for(int btnIdx = 0; btnIdx < buttons.length;
                                btnIdx++) {
                                buttons[btnIdx].setOrder(btnIdx);
                            }
                        }
                        //fill form html elements
                        Htmlelements htmlElements = form.getHtmlelements();
                        if(htmlElements != null) {
                            Htmlelement[] htmlElement = htmlElements
                                    .getHtmlelement();
                            for(int htmlIdx = 0; htmlIdx < htmlElement.length;
                                htmlIdx++) {
                                buttons[htmlIdx].setOrder(htmlIdx);
                            }
                        }
                        //fill form headers
                        Header[] headers = EntityHelper.FormHelper
                                .getLayoutHeaders(form);
                        if(headers.length != 0) {
                            for(int headerIdx = 0; headerIdx < headers.length;
                                headerIdx++) {
                                Header header = headers[headerIdx];
                                header.setForm(form.getName());
                                header.setOrder(headerIdx);
                            }
                        }
                        //fill form filters
                        Filter[] filters = EntityHelper.FormHelper
                                .getFormFilters(form);
                        if(filters.length != 0) {
                            for(int filterIdx = 0; filterIdx < filters.length;
                                filterIdx++) {
                                Filter filter = filters[filterIdx];
                                if (filter.getByFormId() == null)
                                    filter.setByFormId(form.getName());
                            }
                        }
                        //fill form rows and cols
                        Row[] rows = EntityHelper.FormHelper.getLayoutRows(
                                form);
                        if(rows.length != 0) {
                            for(int rowIdx = 0; rowIdx < rows.length; rowIdx++)
                            {
                                Row row = rows[rowIdx];
                                row.setForm(form.getName());
                                row.setOrder(rowIdx);
                                Col[] cols = row.getCol();
                                for(int colIdx = 0; colIdx < cols.length;
                                    colIdx++) {
                                    Col col = cols[colIdx];
                                    col.setForm(form.getName());
                                    col.setRow(rowIdx);
                                    col.setOrder(colIdx);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Deploy focus configs
     *
     * @param focusList list of builded focuses
     */
    private void deployFocusConfigs(List<Focus> focusList) {
        try {
            getFocusConfigManager().fillFocuses(focusList);
        } catch (RemoteException ex) {
            throw new GenericSystemException(
                    "Remote exception. Can`t deploy focus configs: " + ex
                            .getMessage(), ex);
        }
    }

    /**
     * Get FocusConfigManager EJB reference
     *
     * @return FocusConfigManager remote interface
     */
    private FocusConfigManager getFocusConfigManager() {
        return (FocusConfigManager)
                getContext().getCOM().getRemoteObject(
                        JNDINames.FocusConfigManagerRemote,
                        FocusConfigManagerHome.class);
    }
}
