/* 
 * Diplomová práce ÚSI VUT 
 * Forenzní analýza webového prohlížeče
 *
 * Autor: Michal Bača
 * Datum: 20.5.2015
 */
package yafft.Utils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import yafft.FFModel.Model;
import yafft.FFModel.ModelItems.Bookmark;
import yafft.FFModel.ModelItems.CookieValue;
import yafft.FFModel.ModelItems.DownloadsItem;
import yafft.FFModel.ModelItems.FormItem;
import yafft.FFModel.ModelItems.HistoryItem;

/**
 *
 * @author michal
 */
public class XmlOutput {

    Model model;
    ImportExportOptions options;
    Document document;
    //Path outputDir;
    String reportFileName = "report.xml";

    public XmlOutput(Model model) {
        this.model = model;

    }

    public XmlOutput(Model model, ImportExportOptions options) {
        this.model = model;
        this.options = options;
        //this.outputDir = ImportExportOptions.getExportDirectory();
    }

    public ImportExportOptions getOptions() {
        return options;
    }

    public String getReportFileName() {
        return reportFileName;
    }

    public void setReportFileName(String reportFileName) {
        this.reportFileName = reportFileName;
    }

    public void setOptions(ImportExportOptions options) {
        this.options = options;
        //this.outputDir = ImportExportOptions.getExportDirectory();
    }

    public Model getModel() {
        return model;
    }

    public void setModel(Model model) {
        this.model = model;
    }

    private Node createNode(String name, String value) {
        Element el = document.createElement(name);
        el.appendChild(document.createTextNode(value));

        return el;
    }

    public void writeUserInfo() {

    }

    public void writeFilesInfo(FFProfile p, Node root) {

        try {
            List<Path> files = Files.walk(p.getProfile().toPath()).collect(Collectors.toList());
            Element filesRoot = document.createElement("Files");

            for (Path f : files) {
                BasicFileAttributes attr;
                attr = Files.readAttributes(f, BasicFileAttributes.class);
                //System.out.println(attr.creationTime() + "\t" + attr.size() + "\t" + attr.isRegularFile() + "\t" + f + "\t" + Hash.getMD5(f) + "\t"+ Hash.getSHA256(f));
                Element file = document.createElement("file");
                file.setAttribute("regularFile", String.valueOf(attr.isRegularFile()));
                file.setAttribute("size", String.valueOf(attr.size()));
                file.setAttribute("filename", f.toString());

                Node md5 = createNode("md5", Hash.getMD5(f));
                Node sha = createNode("sha256", Hash.getSHA256(f));

                Node added = createNode("creationTime", attr.creationTime().toString());
               // Node modified = createNode("modified", b.getModified().getValue().toString());

                file.appendChild(sha);
                file.appendChild(md5);
                file.appendChild(added);

                filesRoot.appendChild(file);

            }

            root.appendChild(filesRoot);

        } catch (IOException ex) {
            Logger.getLogger(XmlOutput.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void writeHostInfo() {

    }

    private void writeBookmarks(Node root) {
        Element bookmarkRoot = document.createElement("Bookmarks");
        for (Bookmark b : this.model.getBookmarks()) {

            Element bookmark = document.createElement("Bookmark");

            Node url2 = createNode("url", b.getUrl().getName());
            Node added = createNode("creationTime", b.getAdded().getValue().toString());
            Node modified = createNode("modified", b.getModified().getValue().toString());

            bookmark.appendChild(url2);
            bookmark.appendChild(added);
            bookmark.appendChild(modified);
            bookmark.setAttribute("name", b.getName().getValue());

            bookmarkRoot.appendChild(bookmark);

        }
        root.appendChild(bookmarkRoot);
    }

    private void writeDownloads(Node root) {
        Element downloadsRoot = document.createElement("Downloads");

        for (DownloadsItem d : this.model.getDownloads()) {

            Element download = document.createElement("Download");
            //filename
            download.setAttribute("name", d.getFileName().getValue());
            //source
            Node src = createNode("source", d.getSource().getName());
            download.appendChild(src);
            //dest
            Node dest = createNode("destination", d.getDestination().getName());
            download.appendChild(dest);
            //endtime
            download.setAttribute("finished", d.getEndTime().getValue().toString());
            //size
            download.setAttribute("size", d.getFileSize().getValue().toString());

            downloadsRoot.appendChild(download);

        }
        root.appendChild(downloadsRoot);

    }

    private void writeForms(Node root) {
        Element formsRoot = document.createElement("Forms");

        /*  this.model.getForms().stream().forEach((item) -> {
         });*/
        for (FormItem f : this.model.getForms()) {
            Element form = document.createElement("Form");
            form.setAttribute("id", f.getFieldID().getValue());
            form.setAttribute("firstUsed", f.getFirstUsed().getValue().toString());
            form.setAttribute("lastUsed", f.getLastUsed().getValue().toString());
            form.setAttribute("timesUsed", f.getTimesUsed().getValue().toString());

            Node value = createNode("value", f.getFormValue().getValue());
            form.appendChild(value);
            //form.setAttribute("value", f.getFormValue().getValue());
            formsRoot.appendChild(form);
        }

        root.appendChild(formsRoot);
    }

    private void writeHistory(Node root) {
        Element historyRoot = document.createElement("History");
        for (HistoryItem h : this.model.getHistory()) {

            Element web = document.createElement("website");
            web.setAttribute("name", h.getTitle().getValue());
            web.setAttribute("visitCount", h.getVisitCount().getValue().toString());

            Node url = createNode("url", h.getUrl().getName());
            web.appendChild(url);

            Node visited = createNode("visited", h.getDate().getValue());
            web.appendChild(visited);

            historyRoot.appendChild(web);

        }
        root.appendChild(historyRoot);
    }

    private void writeCookies(Node root) {
        Element cookiesRoot = document.createElement("Cookies");
        root.appendChild(cookiesRoot);

        Iterator i = this.model.getCookies2().iterator();
        Element prevPathRoot = null;
        Element cookie = null;
        Element path = null;
        Element value = null;

        while (i.hasNext()) {

            CookieValue cv = (CookieValue) i.next();

            if (cv.isRoot()) {
                cookie = document.createElement("cookie");
                cookie.setAttribute("domain", cv.getDomain().getValue());

                path = document.createElement("path");
                path.setAttribute("value", cv.getPath().getValue());

                value = document.createElement("value");
                value.setAttribute("key", cv.getKey().getValue());
                value.setAttribute("value", cv.getValue().getValue());
                value.setAttribute("expiry", cv.getExpiry().getValue().toString());
                value.setAttribute("created", cv.getCreationTime().getValue().toString());

                path.appendChild(value);

                cookie.appendChild(path);
                cookiesRoot.appendChild(cookie);

                prevPathRoot = path;

            } else {
                if (prevPathRoot != null) {

                    // path = createNode("path", cv.getPath().getValue());
                    //cookie.appendChild(path);
                    String p = prevPathRoot.getAttribute("value");
                    if (p == null) {
                        //System.out.println("------------>QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ");
                        p = "&@{ĐĐ";
                    }
                    if (p.equals(cv.getPath().getValue())) {
                        value = document.createElement("value");
                        value.setAttribute("key", cv.getKey().getValue());
                        value.setAttribute("value", cv.getValue().getValue());
                        value.setAttribute("expiry", cv.getExpiry().getValue().toString());
                        value.setAttribute("created", cv.getCreationTime().getValue().toString());

                        prevPathRoot.appendChild(value);

                    } else {

                        path = document.createElement("path");
                        path.setAttribute("value", cv.getPath().getValue());

                        value = document.createElement("value");
                        value.setAttribute("key", cv.getKey().getValue());
                        value.setAttribute("value", cv.getValue().getValue());
                        value.setAttribute("expiry", cv.getExpiry().getValue().toString());
                        value.setAttribute("created", cv.getCreationTime().getValue().toString());

                        path.appendChild(value);
                        cookie.appendChild(path);
                        prevPathRoot = path;

                    }

                }

            }

        }
        //end of while

    }

    public Boolean write() {

        if (this.options == null) {
            return false;
        }

        try {

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            Document report = builder.newDocument();
            this.document = report;

            Element root = report.createElement("YaFFtReport");
            Node rootNode = report.appendChild(root);

            if (ImportExportOptions.getBookmarks() == true) {
                System.out.println("XML: zapisuji bookmarks");
                this.writeBookmarks(rootNode);
            }

            if (ImportExportOptions.getDownloads()) {
                System.out.println("XML: zapisuji stahování");
                this.writeDownloads(rootNode);
            }

            if (ImportExportOptions.getForms()) {
                System.out.println("XML: zapisuji formulářě");
                this.writeForms(rootNode);
            }

            if (ImportExportOptions.getHistory()) {
                System.out.println("XML: zapisuji hitorii");
                this.writeHistory(rootNode);
            }

            if (ImportExportOptions.getCookies()) {
                System.out.println("XML: zapisuji cookies");
                this.writeCookies(rootNode);
            }

            System.out.println("XML: zapisuji soubory");
            this.writeFilesInfo(ImportExportOptions.getProfile(), rootNode);

            Transformer t = TransformerFactory.newInstance().newTransformer();
            //t.setOutputProperties(OutputKeys.INDENT);
            t.setOutputProperty(OutputKeys.INDENT, "yes");
            DOMSource src = new DOMSource(report);

            StreamResult output;

            if (ImportExportOptions.getConsoleOutput()) {
                System.out.println("XML: ");
                output = new StreamResult(System.out);
                t.transform(src, output);

            }

            output = new StreamResult(new File(ImportExportOptions.getExportDirectory() + java.io.File.separator + this.getReportFileName()));
            t.transform(src, output);
            System.out.println("File " + ImportExportOptions.getExportDirectory() + java.io.File.separator + this.getReportFileName() + " created");

        } catch (ParserConfigurationException ex) {
            Logger.getLogger(XmlOutput.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TransformerConfigurationException ex) {
            Logger.getLogger(XmlOutput.class.getName()).log(Level.SEVERE, null, ex);
        } catch (TransformerException ex) {
            Logger.getLogger(XmlOutput.class.getName()).log(Level.SEVERE, null, ex);
        }

        return true;
    }

}
