/*
 * $Id: ImportMaintenanceForm.java,v 1.9 2007/11/02 19:52:18 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: ImportMaintenanceForm.java,v $
 * Revision 1.9  2007/11/02 19:52:18  marbobo
 * + Bugfix (Statt List werden HashSet benutzt)
 *
 * Revision 1.8  2007/10/30 14:14:52  marbobo
 * + removed unnecessary statements
 *
 * Revision 1.7  2007/10/25 11:12:48  korowa
 * Benutzer- und GruppenNamen werden ab jetzt in verschiedenen Hashmaps verwaltet
 *
 * Revision 1.6  2007/10/23 07:58:07  korowa
 * MigrationLog hinzugefügt,alle Objekte werden da rausgeschrieben, bugfixing: LastChangerId von User wird jetzt aktualisiert,
 *
 * Revision 1.5  2007/09/19 07:56:05  korowa
 * strengere Regel für ImportDatei
 *
 * Revision 1.4  2007/09/18 14:29:42  korowa
 * bugfixing
 *
 * Revision 1.3  2007/09/18 07:48:28  korowa
 * Anpassung an die Änderung des ArchievCategorie, die Ordnernamen werden jetzt als Id abgelegt und ausgelesen
 *
 * Revision 1.2  2007/09/17 09:29:16  korowa
 * bugfixing
 *
 * Revision 1.1  2007/08/28 12:16:00  korowa
 * Export- und Importfunktionen hinzugefügt
 *
 * Revision 1.13  2005/02/20 23:34:15  marbobo
 * + Bugfix
 *
 * Revision 1.12  2004/11/10 15:02:48  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.11  2004/08/07 00:34:43  marbobo
 * + Bugfix für Zeitangaben und Refactorings
 *
 * Revision 1.10  2004/07/20 08:09:56  jonyp
 * added copyright info + cvs log
 *
 */

package vkc.administration.form;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
import org.apache.struts.util.LabelValueBean;

import com.thoughtworks.xstream.XStream;

import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCDocument;
import vkc.db.entities.VKCGroup;
import vkc.db.entities.VKCMigrationObjects;
import vkc.db.entities.VKCSearchQuery;
import vkc.db.entities.VKCSubCategory;
import vkc.db.entities.VKCUser;
import vkc.db.serializer.VKCCategorySerializer;
import vkc.db.serializer.VKCGroupSerializer;
import vkc.db.serializer.VKCUserSerializer;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;
import vkc.util.StringUtils;
import vkc.util.VKCCategoryAbsPath;
import vkc.util.ZipUtils;
import vkc.view.WebShare;
import vkc.view.bean.GroupInfo;
import vkc.view.bean.UserInfo;

public final class ImportMaintenanceForm extends SystemMaintenanceForm {

    public final int STEP_PREPARE = 1;

    public final int STEP_SHOWCONFLICTS = 2;

    public final int STEP_IMPORT = 3;

    private FormFile importFile = null;

    private HashSet<VKCUser> importUser = null;

    private HashSet<VKCGroup> importGroups = null;

    private HashSet<VKCCategory> importCategories = null;

    private HashSet<VKCDocument> importDocuments = null;

    private List<VKCSearchQuery> importUserQueries = null;

    private HashMap<Integer, VKCSearchQuery> importQueries = null;

    private String[] importUserName = new String[0];

    private String[] importGroupName = new String[0];

    private HashMap categoryIds = new HashMap();

    private HashMap categoryIdsReverse = new HashMap();

    private HashMap userIds = new HashMap();

    private HashMap groupIds = new HashMap();

    private HashMap documentIds = new HashMap();

    private VKCCategory category = null;

    private Integer categoryId = new Integer(1);

    private String conversionResponse = null;

    private boolean selfNameGen = false;

    private List userConflictNames = null;

    private List groupConflictNames = null;

    private int step = STEP_PREPARE;

    private String pathForObjects = "";

    private HashMap conflictUserNames = new HashMap();

    private HashMap conflictGroupNames = new HashMap();

    private List userInfos = null;

    private List groupInfos = null;

    public void reset(ActionMapping mapping, HttpServletRequest request) {
        super.reset(mapping, request);
        
        categoryId = new Integer(1);
        
        if (userInfos == null) {
            userInfos = new ArrayList();
            
            try {
                Iterator iter = VKCUserSerializer.retrieveUserInfos().iterator();
                LabelValueBean label = null;
                
                while (iter.hasNext()) {
                    UserInfo user = (UserInfo) iter.next();
                    label = new LabelValueBean(user.getFullName(), user.getUsername());
                    userInfos.add(label);
                }
            } catch (DBException e) {
                VKCLogManager.errorLog(VKCCategorySerializer.class, "", e.getMessage(), e);
            }
            
            setSelectedContext(SystemMaintenanceForm.IMPORT);
        }
        
        if (groupInfos == null) {
            groupInfos = new ArrayList();
            
            try {
                Iterator iter = VKCGroupSerializer.retrieveGroupInfos().iterator();
                LabelValueBean label = null;
                
                while (iter.hasNext()) {
                    GroupInfo group = (GroupInfo) iter.next();
                    label = new LabelValueBean(group.getName(), group.getName());
                    groupInfos.add(label);
                }
            } catch (DBException e) {
                VKCLogManager.errorLog(VKCCategorySerializer.class, "", e.getMessage(), e);
            }
        }

    }

    /**
     * Validiert die Eingabefelder und gibt gegebenfalls die Fehler zurück
     * 
     * @param mapping
     *            The mapping used to select this instance
     * @param request
     *            The servlet request we are processing
     */
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        
        if (getStep() == this.STEP_PREPARE && request.getParameter("action.import") != null) {
            if (getImportFile() == null || getImportFile().getFileName() == null || StringUtils.normalize(getImportFile().getFileName()).length() == 0) {
                errors.add("file", new ActionError("error.document.no.file"));
            } else if (!importFile.getFileName().endsWith("zip")) {
                errors.add("file", new ActionError("error.document.file.false"));
            }
        }
        
        synchronizeConflictNames(errors);
        
        return errors;
    }

    private ActionErrors synchronizeConflictNames(ActionErrors errors) {
        conflictUserNames = new HashMap();
        conflictGroupNames = new HashMap();
        LabelValueBean conflictName = null;
        String conflict = "";
        
        if (userConflictNames != null && userConflictNames.size() > 0) {
            Iterator iter = getUserConflictNames().iterator();
            
            while (iter.hasNext()) {
                conflictName = (LabelValueBean) iter.next();
                
                if (getImportUserName() != null && containsImportName(getImportUserName(), conflictName.getValue()) && !conflictName.getValue().equals(conflictName.getLabel())) {
                    if (conflict.indexOf(conflictName.getValue()) == -1) {
                        if (conflict.equals("")) {
                            conflict += conflictName.getValue();
                        } else {
                            conflict += ", " + conflictName.getValue();
                        }
                    }
                }
                
                if (!conflictName.getValue().equals("")) {
                    if (!conflictUserNames.containsValue(conflictName.getValue())) {
                        conflictUserNames.put(conflictName.getLabel(), conflictName.getValue());
                    } else if (conflict.indexOf(conflictName.getValue()) == -1) {// falls
                        // noch
                        // nicht
                        // vorhanden
                        if (conflict.equals("")) {
                            conflict += conflictName.getValue();
                        } else {
                            conflict += ", " + conflictName.getValue();
                        }
                    }
                }
            }
        }
        
        if (groupConflictNames != null && groupConflictNames.size() > 0) {
            Iterator iter = getGroupConflictNames().iterator();
            
            while (iter.hasNext()) {
                conflictName = (LabelValueBean) iter.next();
                
                if (getImportGroupName() != null && containsImportName(getImportGroupName(), conflictName.getValue()) && !conflictName.getValue().equals(conflictName.getLabel())) {
                    if (conflict.indexOf(conflictName.getValue()) == -1) {
                        if (conflict.equals("")) {
                            conflict += conflictName.getValue();
                        } else {
                            conflict += ", " + conflictName.getValue();
                        }
                    }
                }
                
                if (!conflictName.getValue().equals("")) {
                    if (!conflictGroupNames.containsValue(conflictName.getValue())) {
                        conflictGroupNames.put(conflictName.getLabel(), conflictName.getValue());
                    } else if (conflict.indexOf(conflictName.getValue()) == -1) {// falls
                        // noch
                        // nicht
                        // vorhanden
                        if (conflict.equals("")) {
                            conflict += conflictName.getValue();
                        } else {
                            conflict += ", " + conflictName.getValue();
                        }
                    }
                }
            }
        }

        if (!conflict.equals("")) {
            errors.add("", new ActionError("error.username_in_use", conflict));
            step = this.STEP_SHOWCONFLICTS;
        }
        
        return errors;
    }

    public HashSet getImportCategories() {
        return importCategories;
    }

    public void setImportCategories(HashSet importCategories) {
        this.importCategories = importCategories;
    }

    public HashSet getImportGroups() {
        return importGroups;
    }

    public void setImportGroups(HashSet importGroups) {
        this.importGroups = importGroups;
    }

    public HashSet getImportUser() {
        return importUser;
    }

    public void setImportUser(HashSet importUser) {
        this.importUser = importUser;
    }

    public FormFile getImportFile() {
        return importFile;
    }

    public void setImportFile(FormFile importFile) {
        this.importFile = importFile;
    }

    public String getArchiveDirectoryPath() {
        return getArchiveDirectory().getAbsolutePath();
    }

    public File getArchiveDirectory() {
        File file = null;
        String path = WebShare.getSysParameterValue("ARCHIVECATEGORY", "ArchiveCategoryPath", "");

        if (!isEmpty(path)) {
            file = new File(path);
        } else {
            file = new File(WebShare.getWebApplicationDir(), "WEB-INF/archives");
        }

        return file.getAbsoluteFile();
    }

    public HashMap getCategoryIds() {
        return categoryIds;
    }

    public void setCategoryIds(HashMap categoryIds) {
        this.categoryIds = categoryIds;
    }

    public HashMap getGroupIds() {
        return groupIds;
    }

    public void setGroupIds(HashMap groupIds) {
        this.groupIds = groupIds;
    }

    public HashMap getUserIds() {
        return userIds;
    }

    public void setUserIds(HashMap userIds) {
        this.userIds = userIds;
    }

    public VKCCategory getCategory() {
        if (category == null) {
            try {
                this.setCategory(VKCCategorySerializer.retrieveCategory(getCategoryId()));
            } catch (DBException e) {
                VKCLogManager.errorLog(VKCCategorySerializer.class, "", e.getMessage(), e);
            }
        }
        
        return category;
    }

    public void setCategory(VKCCategory category) {
        this.category = category;
    }

    public String getCategoryPath() {
        VKCCategoryAbsPath cap = null;
        Integer categoryId = null;

        categoryId = new Integer(getCategoryId().intValue());

        try {
            cap = VKCCategorySerializer.getCategoryAbsPath(categoryId);
        } catch (DBException e) {
        }

        if (cap == null) {
            return getResources().getMessage(getLocale(), "vkc.profile.error.homecategory");
        }

        return cap.getAbsolutePathString();
    }

    public HashMap getImportCategoryParams() {
        HashMap params = new HashMap();
        params.put("categoryId", getCategoryId());

        return params;
    }

    public Integer getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Integer id) {
        categoryId = id;
    }

    public HashMap getDocumentIds() {
        return documentIds;
    }

    public void setDocumentIds(HashMap documentIds) {
        this.documentIds = documentIds;
    }

    /*
     * Stellt den Pfad für Kategory zusammen für die angegebene KategorieId
     */
    public String getPath(int catId) throws DBException {
        String path = "";
        VKCCategory catTemp = null;
        Integer tempId = new Integer(catId);
        Integer categoryIdName = null;
        
        do {
            Iterator iterCat = this.getImportCategories().iterator();
            
            while (iterCat.hasNext()) {
                catTemp = (VKCCategory) iterCat.next();
                
                if (catTemp.getCategoryId().intValue() == tempId.intValue()) {
                    categoryIdName = (Integer) getCategoryIdsReverse().get(tempId);
                    tempId = catTemp.getParentCategoryId();
                    path = File.separator + categoryIdName + path;
                    break;
                }
            }

        } while (this.getCategoryIds().containsValue(tempId));

        return this.getArchiveDirectoryPath() + path;
    }

    public HashSet getImportDocuments() {
        return importDocuments;
    }

    /*
     * Sortiert ArrayList von Kategorien mit Wurzel als erstes Element und Blätter als letzte elemente
     */
    public void sortSet(VKCCategory root, ArrayList list) {
        list.add(root);
        Iterator iter = root.getSubCategories().iterator();
        
        while (iter.hasNext()) {
            sortSet(getImportedCategory(((VKCSubCategory) iter.next()).getSubCategoryId()), list);
        }
    }

    /*
     * Gibt die gewünschte Kategorie aus der Liste von zu importierenden Kategorien aus
     */
    private VKCCategory getImportedCategory(Integer subCategoryId) {
        Iterator iter = getImportCategories().iterator();
        
        while (iter.hasNext()) {
            VKCCategory cat = (VKCCategory) iter.next();
            
            if (cat.getCategoryId().intValue() == subCategoryId.intValue()) {
                return cat;
            }
        }
        
        return null;
    }

    public void setImportDocuments(HashSet importDocuments) {
        this.importDocuments = importDocuments;
    }

    public String getConversionResponse() {
        return conversionResponse;
    }

    public void setConversionResponse(String conversionResponse) {
        this.conversionResponse = conversionResponse;
    }

    public boolean isSelfNameGen() {
        return selfNameGen;
    }

    public void setSelfNameGen(boolean selfNameGen) {
        this.selfNameGen = selfNameGen;
    }

    public List getGroupConflictNames() {
        return groupConflictNames;
    }

    public void setGroupConflictNames(List groupNames) {
        this.groupConflictNames = groupNames;
    }

    public List getUserConflictNames() {
        return userConflictNames;
    }

    public void setUserConflictNames(List userNames) {
        this.userConflictNames = userNames;
    }

    /*
     * Entpackt den Zipfile(Importfile) und setzt die zu importierende Objekte: Kategorien, Dokumenten, Gruppen, Benutzer, SearchQuerries
     */
    public ActionErrors unzip() {
        ActionErrors errors = new ActionErrors();
        ZipFile importFile = null;
        File importInput = null;
        File documents = null;
        File targetDirectory = getArchiveDirectory();
        InputStream importInputStream;
        
        try {
            importInputStream = getImportFile().getInputStream();
            importInput = new File("Import");
            OutputStream importOutput = new FileOutputStream(importInput);
            
            if (!targetDirectory.exists()) {
                targetDirectory.mkdirs();
                targetDirectory.mkdir();
            }
            
            byte buffer[] = new byte[0xffff];
            int nbytes;
            
            while ((nbytes = importInputStream.read(buffer)) != -1) {
                importOutput.write(buffer, 0, nbytes);
            }
            
            importOutput.close();
            importInputStream.close();
            importFile = new ZipFile(importInput);

            for (Enumeration e = importFile.entries(); e.hasMoreElements();) {
                ZipEntry entry = (ZipEntry) e.nextElement();
                
                if (entry.getName().equals("Objects.xml")) {
                    File objects = new File(targetDirectory, entry.getName());
                    FileOutputStream fos = new FileOutputStream(objects);
                    BufferedInputStream bis = new BufferedInputStream(importFile.getInputStream(entry));
                    int bytesIn = 0;
                    byte[] readBuffer = new byte[4000];
                    
                    while ((bytesIn = bis.read(readBuffer)) != -1) {
                        fos.write(readBuffer, 0, bytesIn);
                    }
                    
                    fos.close();
                    bis.close();
                    this.setPathForObjects(objects.getCanonicalPath());

                    bis = new BufferedInputStream(importFile.getInputStream(entry));

                    XStream xstream = new XStream();
                    VKCMigrationObjects importObjects = (VKCMigrationObjects) xstream.fromXML(bis);
                    this.setImportCategories(importObjects.getMigrationCategories());
                    this.setImportDocuments(importObjects.getMigrationDocuments());
                    this.setImportGroups(importObjects.getMigrationGroups());
                    this.setImportUser(importObjects.getMigrationUsers());
                    this.setImportQueries(importObjects.getMigrationCategoryQueries());
                    this.setImportUserQueries(importObjects.getMigrationUserQueries());
                    bis.close();
                } else if (entry.getName().equals("ArchiveFile.7z")) {
                    documents = new File(entry.getName());
                    FileOutputStream fos = new FileOutputStream(documents);
                    byte[] readBuffer = new byte[2156];
                    int bytesIn = 0;
                    InputStream fis = importFile.getInputStream(entry);
                    
                    while ((bytesIn = fis.read(readBuffer)) != -1) {
                        fos.write(readBuffer, 0, bytesIn);
                    }
                    
                    fis.close();
                    fos.flush();
                    fos.close();
                    // Documente entpacken
                    ZipUtils.sevenUnZip(documents, targetDirectory);
                }
            }
            
            importFile.close();
        } catch (FileNotFoundException e1) {
            VKCLogManager.errorLog(VKCCategorySerializer.class, "", e1.getMessage(), e1);
            errors.add("file", new ActionError("error.document.file.false"));
        } catch (IOException e1) {
            VKCLogManager.errorLog(VKCCategorySerializer.class, "", e1.getMessage(), e1);
        } finally {
            if (importInput != null) {
                importInput.delete();
            }
            
            if (documents != null) {
                documents.delete();
            }
        }
        
        if (documents == null || getImportCategories() == null) {
            errors.add("file", new ActionError("error.document.file.false"));
        }
        
        setNames();
        
        return errors;
    }

    /*
     * Speichert Die Namen von Usern und Gruppen ab, um die nach möglichen Konflikte mit aktuellen Objekten zu testen
     */
    private void setNames() {
        // Namen von allen Usern in einer Liste abspeichern
        if (getImportUser() != null && getImportUser().size() > 0) {
            String[] names = new String[getImportUser().size()];
            Iterator iterUser = getImportUser().iterator();
            int i = 0;
            
            while (iterUser.hasNext()) {
                VKCUser user = (VKCUser) iterUser.next();
                names[i] = user.getUser();
                i++;
            }
            
            setImportUserName(names);
        }
        
        if (getImportGroups() != null && getImportGroups().size() > 0) {
            String[] namesGroup = new String[getImportGroups().size()];
            Iterator iterGroup = getImportGroups().iterator();
            int i = 0;
            
            while (iterGroup.hasNext()) {
                VKCGroup group = (VKCGroup) iterGroup.next();
                namesGroup[i] = group.getName();
                i++;
            }

            setImportGroupName(namesGroup);
        }
    }

    /*
     * Gibt aktuellen Zustand von Importfunktion
     */
    public int getStep() {
        return step;
    }

    public void setStep(int step) {
        this.step = step;
    }

    /*
     * Gibt den Pfad zu XMLFile mit importierten Objekten
     */
    public String getPathForObjects() {
        return pathForObjects;
    }

    /*
     * Setzt den Pfad zu XMLFile mit importierten Objekten
     */
    public void setPathForObjects(String pfadForObjects) {
        this.pathForObjects = pfadForObjects;
    }

    public LabelValueBean getUserName(int index) {
        if (userConflictNames == null) {
            setUserConflictNames(new ArrayList());
        }
        
        if (index >= userConflictNames.size()) { // Array vergrössern
            for (int i = userConflictNames.size(); i <= index; i++) {
                userConflictNames.add(new LabelValueBean("", ""));
            }
        }

        return (LabelValueBean) userConflictNames.get(index);
    }

    public LabelValueBean getGroupName(int index) {
        if (groupConflictNames == null) {
            setGroupConflictNames(new ArrayList());
        }
        
        if (index >= groupConflictNames.size()) { // Array vergrössern
            for (int i = groupConflictNames.size(); i <= index; i++) {
                groupConflictNames.add(new LabelValueBean("", ""));
            }
        }

        return (LabelValueBean) groupConflictNames.get(index);
    }

    /*
     * Generiert einen Namen für Benutzer
     */
    public String getNewUserName(String name) {
        if (conflictUserNames.containsKey(name)) {
            return (String) conflictUserNames.get(name);
        } else {
            try {
                name += "_mig";
                
                while (VKCUserSerializer.isUserExistent(name) || containsImportName(getImportUserName(), name)) {
                    name += "_mig";
                }
                
                return name;
            } catch (DBException e) {
                VKCLogManager.errorLog(VKCCategorySerializer.class, "", e.getMessage(), e);
            }
        }
        
        return name;
    }

    /*
     * Generiert einen Namen für Gruppe
     */
    public String getNewGroupName(String name) {
        if (conflictGroupNames.containsKey(name)) {
            return (String) conflictGroupNames.get(name);
        } else {
            try {
                name += "_mig";
                
                while (VKCGroupSerializer.isGroupExistent(name) || containsImportName(getImportGroupName(), name)) {
                    name += "_mig";
                }
            } catch (DBException e) {
                VKCLogManager.errorLog(VKCCategorySerializer.class, "", e.getMessage(), e);
            }
        }
        
        return name;
    }

    public HashMap getConflictUserNames() {
        return conflictUserNames;
    }

    public HashMap getConflictGroupNames() {
        return conflictGroupNames;
    }

    /*
     * Liefert die gesuchte Gruppe(GruppenId) aus der Liste
     */
    public VKCGroup getGroup(Integer id) {
        Iterator iter = getImportGroups().iterator();
        
        while (iter.hasNext()) {
            VKCGroup group = (VKCGroup) iter.next();
            
            if (group.getGroupId().equals(id)) {
                return group;
            }
        }
        
        return null;
    }

    public List getUserInfos() {
        return userInfos;
    }

    public void setUserInfos(List userInfos) {
        this.userInfos = userInfos;
    }

    public List getGroupInfos() {
        return groupInfos;
    }

    public void setGroupInfos(List groupInfos) {
        this.groupInfos = groupInfos;
    }

    public String[] getImportGroupName() {
        return importGroupName;
    }

    public void setImportGroupName(String[] importGroupName) {
        this.importGroupName = importGroupName;
    }

    public String[] getImportUserName() {
        return importUserName;
    }

    public void setImportUserName(String[] importUserName) {
        this.importUserName = importUserName;
    }

    public boolean containsImportName(String[] importNames, String name) {
        if (importNames.length == 0) {
            return false;
        }
        
        for (int i = 0; i < importNames.length; i++) {
            if (importNames[i] != null && importNames[i].equals(name)) {
                return true;
            }
        }
        
        return false;
    }

    public void addImportName(String[] importNames, String name) {
        List addedImportNames = new ArrayList(Arrays.asList(importNames));
        addedImportNames.add(name);
        importNames = (String[]) (addedImportNames.toArray(new String[addedImportNames.size()]));
    }

    public void setImportQueries(HashMap<Integer, VKCSearchQuery> migrationQueries) {
        this.importQueries = migrationQueries;

    }

    public HashMap<Integer, VKCSearchQuery> getImportQueries() {
        return importQueries;
    }

    public List<VKCSearchQuery> getImportUserQueries() {
        return importUserQueries;
    }

    public void setImportUserQueries(List<VKCSearchQuery> importUserQueries) {
        this.importUserQueries = importUserQueries;
    }

    public HashMap getCategoryIdsReverse() {
        return categoryIdsReverse;
    }

    public void setCategoryIdsReverse(HashMap categoryIdsReverse) {
        this.categoryIdsReverse = categoryIdsReverse;
    }
}