package info.bukova.isspst.ui.signeddocs;

import info.bukova.isspst.DateTimeUtils;
import info.bukova.isspst.data.SignedDocument;
import info.bukova.isspst.data.SignedDocumentItem;
import info.bukova.isspst.storage.ReportFileStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.zk.ui.select.annotation.WireVariable;
import org.zkoss.zul.DefaultTreeModel;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.TreeModel;
import org.zkoss.zul.TreeNode;

import java.io.*;
import java.text.Normalizer;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


public class SignedDocsTreeList extends SignedDocsList {
    @SuppressWarnings("unused")
    private final static Logger log = LoggerFactory.getLogger(SignedDocsTreeList.class.getName());

    @WireVariable
    private ReportFileStorage signedDocStorage;

    public SignedDocsTreeNode getSelectedNodeItem() {
        return selectedNodeItem;
    }

    public void setSelectedNodeItem(SignedDocsTreeNode selectedNodeItem) {
        this.selectedNodeItem = selectedNodeItem;
    }

    private SignedDocsTreeNode selectedNodeItem;

    public SignedDocsTreeList() {
    }

    @Init(superclass = true)
    public void signedDocsTreeListInit() {
    }

    public TreeModel<TreeNode<SignedDocumentItem>> getTreeBackup() {
        try {
            return signedDocumentService.getTree();
        } catch (AccessDeniedException e) {
            // BindUtils.postGlobalCommand(null, null, "disableCentre", null);
            // e.printStackTrace();
            return new DefaultTreeModel<SignedDocumentItem>(null);
        }
    }

    public static void addToZipFile(String filePath, String zipPath, ZipOutputStream zos) throws FileNotFoundException, IOException {

        //System.out.println("Writing '" + filePath + "' to zip file");

        File file = new File(filePath);
        FileInputStream fis = new FileInputStream(file);
        ZipEntry zipEntry = new ZipEntry(zipPath);
        zos.putNextEntry(zipEntry);

        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zos.write(bytes, 0, length);
        }

        zos.closeEntry();
        fis.close();
    }

    public static String getNormalizedPath(String path) {
        String result = path.replaceAll("[ ]", "_");
        result = Normalizer.normalize(result, Normalizer.Form.NFD);
        result = result.replaceAll("[^-a-zA-Z0-9_./]", "");
        return result;
    }

    public static String getCheckedString(String str, int maxLength) {
        String result = "";

        if (str != null) {

            int len = str.length();

            if (len > 0) {
                result = str.substring(0, len > maxLength ? maxLength - 1 : len);
                result += "-";
            }
        }

        return result;
    }

    public static String getCheckedString(String str) {
        return SignedDocsTreeList.getCheckedString(str, 50);
    }

    @Command
    public void onCreateZipArchive() {
        if (this.selectedNodeItem == null) {
            return;
        }

        List<SignedDocsTreeNode> leafs = this.selectedNodeItem.getLeafs();

        if (leafs.size() > 0) {
            int deep = this.selectedNodeItem.getDeep();

            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ZipOutputStream zos = new ZipOutputStream(bos);

                for (SignedDocsTreeNode node : leafs) {
                    SignedDocumentItem item = node.getData();
                    String pdfFileName = item.getFileName();

                    SignedDocument doc = item.getSignedDocument();
                    String zipDirs = "";


                    String zipFileName = "";

                    if (deep == 3 || deep == 4) {
                        zipFileName += SignedDocsTreeList.getCheckedString(DateTimeUtils.getFormatedDirDate(doc.getSignDate()));
                    }

                    zipFileName += SignedDocsTreeList.getCheckedString(item.getReportName());
                    zipFileName += SignedDocsTreeList.getCheckedString(doc.getNumser());
                    zipFileName += SignedDocsTreeList.getCheckedString(doc.getDescription());
                    zipFileName += SignedDocsTreeList.getCheckedString(pdfFileName);

                    if (deep == 1 || deep == 2 || deep == 3) {
                        zipDirs += doc.getAgendaName();
                        zipDirs += "/";
                    }

                    if (deep == 1) {
                        zipDirs += DateTimeUtils.getFormatedYear(doc.getSignDate());
                        zipDirs += "/";
                    }

                    if (deep == 1) {
                        zipDirs += DateTimeUtils.getFormatedDirDateDDMM(doc.getSignDate());
                        zipDirs += "/";
                    }
                    if (deep == 2) {
                        zipDirs += DateTimeUtils.getFormatedDirDate(doc.getSignDate());
                        zipDirs += "/";
                    }
                    String rootPath = signedDocStorage.getRootPath();

                    String diskPath = rootPath + "/" + pdfFileName;
                    String zipPath = zipDirs + zipFileName;

                    zipPath = SignedDocsTreeList.getNormalizedPath(zipPath);

                    if (new File(diskPath).isFile()) {
                        SignedDocsTreeList.addToZipFile(diskPath, zipPath, zos);
                    } else {
                        log.warn("Missing file '" + diskPath + "' !!!");
                        log.warn(doc.getAgendaName());
                        log.warn(doc.getDescription());
                        log.warn(item.getReportName());
                    }
                }

                zos.close();
                bos.close();

                Filedownload.save(bos.toByteArray(), "application/zip", "temp" + Long.toString(System.nanoTime()) + ".zip");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
