/*
 * 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.jxb.entity.Entity;
import com.queplix.core.modules.config.ejb.CaptionManager;
import com.queplix.core.modules.config.ejb.CaptionManagerHome;
import com.queplix.core.modules.config.ejb.CustomConfigManager;
import com.queplix.core.modules.config.ejb.CustomConfigManagerHome;
import com.queplix.core.modules.config.ejb.EntityViewConfigManager;
import com.queplix.core.modules.config.ejb.EntityViewConfigManagerHome;
import com.queplix.core.modules.config.jxb.Custom;
import com.queplix.core.modules.config.jxb.Customs;
import com.queplix.core.modules.config.jxb.Messages;
import com.queplix.core.modules.config.jxb.Popup;
import com.queplix.core.modules.config.jxb.Server;
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.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

/**
 * <p>Action wich fills some customization attributues (captions, messages)
 * from XML files</p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:30:12 $
 */

public class CustomInstallationAction
        extends Action {

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

    private Customs[] customArray;
    private HashMap customTable = new HashMap();
    private Messages[] messageArray;

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

    private String customdir;
    private String i18ndir;

    private File customDirFile;
    private File i18nDirFile;

    /*
     * No javadoc
     * @see Action#perform
     */
    public java.io.Serializable perform() {

        this.customdir = getContext().getParamAsString("customdir");
        this.i18ndir = getContext().getParamAsString("i18ndir");

        if(customdir == null) {
            throw new NullPointerException("Custom dir is NULL");
        }

        if(i18ndir == null) {
            throw new NullPointerException("I18 dir is NULL");
        }

        customDirFile = new File(customdir);
        if(!customDirFile.exists() || !customDirFile.isDirectory()) {
            throw new IllegalStateException("Bad custom config dir: " +
                    customDirFile.getAbsolutePath());
        }

        i18nDirFile = new File(i18ndir);
        if(!i18nDirFile.exists() || !i18nDirFile.isDirectory()) {
            throw new IllegalStateException("Bad i18n config dir: " +
                    i18nDirFile.getAbsolutePath());
        }

        try {

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

            parseMessages();
            deployMessages();

            parseCustoms();
            buildCustomList();
            deployCustomConfigs();

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

        } catch (GenericSystemException ex) {
            ERROR(ex);
            throw ex;

        } catch (Throwable t) {
            ERROR(t);
            throw new GenericSystemException(
                    "Unknown exception: " + t.getMessage(), t);
        }

        return null;
    }

    /**
     * Parse custom xml configs and create Custom objects
     */
    private void parseCustoms() {

        // get list of files
        File[] files = customDirFile.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                String ext = CONFIG_FILES_EXTENSION;
                if(name.substring(name.length() - ext.length()).equals(ext)) {
                    return true;
                } else {
                    return false;
                }
            }
        });
        if(files.length == 0) {
            //throw new IllegalStateException( "Can`t find any XML configs in path '" +
            //                                 customDirFile.getAbsolutePath() + "'" );
            WARN("Can`t find any XML configs in path '"
                    + customDirFile.getAbsolutePath() + "'");
            customArray = new Customs[0];
            return;
        }

        // initialise Custom array
        customArray = new Customs[files.length];

        try {
            // cycle read custom config files
            for(int i = 0; i < files.length; i++) {
                INFO("  read from " + files[i].getCanonicalPath());

                // build Customs object
                Document document = xmlWrapper.getDocument(files[i], false);
                customArray[i] = (Customs) xmlBind.xmlToJava(Customs.class,
                        document);
            }

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

    /**
     * Parse i18n messages xml configs and create Messages objects
     */
    private void parseMessages() {

        // get list of files
        File[] files = i18nDirFile.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                String ext = CONFIG_FILES_EXTENSION;
                if(name.substring(name.length() - ext.length()).equals(ext)) {
                    return true;
                } else {
                    return false;
                }
            }
        });
        if(files.length == 0) {
            //throw new GenericSystemException( "Can`t find any XML configs in path '" +
            //                                  i18nDirFile.getAbsolutePath() + "'" );
            WARN("Can`t find any XML configs in path '"
                    + i18nDirFile.getAbsolutePath() + "'");
            messageArray = new Messages[0];
            return;
        }
        // initialise Messages array
        messageArray = new Messages[files.length];

        try {
            // cycle read config files
            for(int i = 0; i < files.length; i++) {
                INFO("  read from " + files[i].getCanonicalPath());

                // build Messages object
                Document document = xmlWrapper.getDocument(files[i], false);
                messageArray[i] = (Messages) xmlBind.xmlToJava(Messages.class,
                        document);
            }

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

    /**
     * Construct Custom list using array of Custom
     */
    private void buildCustomList() {

        // cycle to select all Customs objects
        for(int i = 0; i < customArray.length; i++) {
            Customs customs = customArray[i];
            int customsSize = customs.getCustomCount();

            // cycle to select all Custom object
            for(int j = 0; j < customsSize; j++) {
                Custom custom = customs.getCustom(j);
                String entityName = custom.getEntity();

                // add custom to map (link with entity name)
                customTable.put(entityName, custom);
                INFO("  build custom '" + entityName + "'");
            }
        }
    }

    /**
     * Try to find suited Custom by the entity name
     *
     * @param entityName entity name
     * @return Custom or null
     */
    private Custom findSuitedCustomConfig(String entityName) {

        Object o = customTable.get(entityName);
        if(o != null) {
            return (Custom) o;
        }

        String entityParentName = EntityHelper.getParentEntityName(entityName);
        if(entityParentName == null) {
            return null;
        }

        return findSuitedCustomConfig(entityParentName);
    }

    /**
     * Deploy custom configs to the EJB
     */
    private void deployCustomConfigs() {

        ArrayList customList = new ArrayList();
        EntityViewConfigManager entityViewConfigManager
                = getEntityViewConfigManager();
        CustomConfigManager customConfigManager = getCustomConfigManager();

        try {
            Collection entityViewConfigs = entityViewConfigManager
                    .getEntityViewConfigs();

            if(entityViewConfigs.isEmpty()) {
                throw new GenericSystemException("Please, fill entities first");
            }

            for(Iterator it = entityViewConfigs.iterator(); it.hasNext();) {
                Entity entity = (Entity) it.next();
                String entityName = entity.getName();

                // get Custom for entity
                Custom custom = findSuitedCustomConfig(entityName);
                if(custom != null) {
                    Custom clonedCustom = (Custom) xmlBind.clone(custom,
                            Custom.class);

                    // set entity name
                    clonedCustom.setEntity(entityName);

                    // add in list
                    customList.add(clonedCustom);
                }
            }

            // deploy custom configs
            int size = customList.size();

            DEBUG(" begin fillCustomConfigs. Size:" + size);

            if(size > 0) {
                customConfigManager.fillCustomConfigs(
                        (Custom[]) customList.toArray(new Custom[0]));
            }

            DEBUG(" fillCustomConfigs - ok.");

        } catch (RemoteException ex) {
            ERROR(ex);
            throw new GenericSystemException(
                    "Remote exception. Can`t deploy custom configs: " + ex
                            .getMessage(),
                    ex);
        }
    }

    /**
     * Deploy messages to the EJB
     */
    private void deployMessages() {

        CaptionManager captionManager = getCaptionManager();

        try {
            int size = messageArray.length;
            for(int i = 0; i < size; i++) {
                Messages msgs = messageArray[i];
                int count = msgs.getServerCount();
                for(int j = 0; j < count; j++) {
                    Server s = msgs.getServer(j);
                    captionManager.fillServerMessages(s.getId(),
                            s.getCaptions());
                }
                DEBUG(" fillServerMessages - ok. Size:" + count);

                // Try to fill popup captions
                count = msgs.getPopupCount();
                for(int j = 0; j < count; j++) {
                    Popup p = msgs.getPopup(j);
                    captionManager.fillPopupMenuCaptions(p.getId(),
                            p.getCaptions());
                }

                DEBUG(" fillPopupCaptions - ok. Size:" + count);
            }

        } catch (RemoteException ex) {
            ERROR(ex);
            throw new GenericSystemException(
                    "Remote exception. Can`t deploy i18n messages: " + ex
                            .getMessage(), ex);
        }
    }

    /**
     * Get EntityViewConfigManager EJB reference
     *
     * @return EntityViewConfigManager remote interface
     */
    private EntityViewConfigManager getEntityViewConfigManager() {
        return (EntityViewConfigManager)
                getContext().getCOM().getRemoteObject(
                        JNDINames.EntityViewConfigManagerRemote,
                        EntityViewConfigManagerHome.class);
    }

    /**
     * Get CustomConfigManager EJB reference
     *
     * @return CustomConfigManager remote interface
     */
    protected CustomConfigManager getCustomConfigManager() {
        return (CustomConfigManager)
                getContext().getCOM().getRemoteObject(
                        JNDINames.CustomConfigManagerRemote,
                        CustomConfigManagerHome.class);
    }

    /**
     * Get CaptionManager EJB reference
     *
     * @return CaptionManager remote interface
     */
    protected CaptionManager getCaptionManager() {
        return (CaptionManager)
                getContext().getCOM().getRemoteObject(
                        JNDINames.CaptionManagerRemote,
                        CaptionManagerHome.class);
    }
}
