package uk.ac.reload.editor.upload;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import uk.ac.reload.diva.prefs.UserPrefs;
import uk.ac.reload.dweezil.gui.layout.XYConstraints;
import uk.ac.reload.dweezil.gui.layout.XYLayout;
import uk.ac.reload.editor.prefs.EditorPrefs;
import uk.ac.reload.editor.upload.repository.uvigo.RepositoryClient;

/**
 *
 * @author Gonzalo
 */
public class UploadProgressPanel extends JPanel {

    /**
     * The global upload progress bar
     */
    private JProgressBar jpbGlobal;
    /**
     * The prograss bar for the current file being uploaded
     */
    private JProgressBar jpbFile;
    /**
     * The percentage progress label
     */
    private JLabel jl;
    /**
     * The label for showing the amount of bytes currently uploaded
     */
    private JLabel jl2;
    /**
     * The information label
     */
    private JLabel jLabelInfo;
    /**
     * The label displaying the current file being uploaded
     */
    private JLabel jLabelUploading;
    /**
     * The upload Thread
     */
    private Thread oThread;
    /**
     * The upload button
     */
    private JButton oBtnUpload;
    /**
     * The cancel upload button
     */
    private JButton oBtnCancel;
    /**
     * The course folder we are going to upload
     */
    private File courseFolderFile;

    /**
     * Constructor
     */
    public UploadProgressPanel() {
        setLayout(new XYLayout());
        constructFields();
    }

    /**
     * Set up the fields
     */
    private void constructFields() {
        int x = 10;
        int y = 10;

        //The information Label
        jLabelInfo = new JLabel("Press \"Upload\" to start!");
        add(jLabelInfo, new XYConstraints(x + 10, y, 0, 0));

        //The label for displaying the file being uploaded
        jLabelUploading = new JLabel("");
        add(jLabelUploading, new XYConstraints(x + 10, y + 25, 0, 0));


        //The label containing the text "File progress"
        JLabel jLabelFileProgress = new JLabel("File progress");
        add(jLabelFileProgress, new XYConstraints(x + 10, y + 150, 0, 20));

        //The label contaning the text "Total progress"
        JLabel jLabelTotalProgress = new JLabel("Total progress");
        add(jLabelTotalProgress, new XYConstraints(x + 10, y + 180, 0, 20));

        //The current file progress bar
        jpbFile = new JProgressBar();
        jpbFile.setMaximum(100);
        jpbFile.setMinimum(0);
        jpbFile.setValue(0);
        jpbFile.setStringPainted(true);
        add(jpbFile, new XYConstraints(x + 100, y + 150, 350, 20));

        //The global progress bar
        jpbGlobal = new JProgressBar();
        jpbGlobal.setMaximum(100);
        jpbGlobal.setMinimum(0);
        jpbGlobal.setValue(0);
        jpbGlobal.setStringPainted(true);
        add(jpbGlobal, new XYConstraints(x + 100, y + 180, 350, 20));

        //The percentage label
        jl = new JLabel("NaN/NaN", SwingConstants.RIGHT);
        jl.setAlignmentX(JLabel.RIGHT_ALIGNMENT);
        add(jl, new XYConstraints(x + 460, y + 180, 90, 20));

        //This label shows the amount of bytes uploaded for the current file
        jl2 = new JLabel("NaN/NaN", SwingConstants.RIGHT);
        add(jl2, new XYConstraints(x + 460, y + 150, 90, 20));


        //The cancel button
        oBtnCancel = new JButton("Cancel");
        oBtnCancel.setEnabled(false);
        oBtnCancel.addActionListener(new CancelUpload());
        add(oBtnCancel, new XYConstraints(x + 215, y + 220, 75, 22));

        //The upload button
        oBtnUpload = new JButton("Upload");
        oBtnUpload.addActionListener(new LoadBar());
        add(oBtnUpload, new XYConstraints(x + 300, y + 220, 75, 22));
    }

    public void setCourseFolder(File courseFolderFile) {
        this.courseFolderFile = courseFolderFile;
    }

    public void reset() {
        if (oThread != null) {
            oThread.interrupt();
            oThread = null;
        }
        jpbGlobal.setEnabled(true);
        jLabelInfo.setText("Press \"Upload\" to start!");
        jpbGlobal.setValue(0);
        jpbFile.setValue(0);
        jl.setText("NaN/NaN");
        jl2.setText("NaN/NaN");
        oBtnUpload.setEnabled(true);
        oBtnCancel.setEnabled(false);
    }

    private class CancelUpload extends AbstractAction {

        public void actionPerformed(ActionEvent e) {
            if (oThread != null) {
                oThread.interrupt();
            }
            jpbGlobal.setEnabled(false);
            //jpb.setBackground(Color.GRAY);
            //jpb.setForeground(Color.GRAY);
            jl.setText("##%");
            oBtnCancel.setEnabled(false);
            jLabelInfo.setText("The user canceled the upload");
        }
    }

    private class LoadBar extends AbstractAction {

        public void actionPerformed(ActionEvent e) {
            oBtnUpload.setEnabled(false);
            oBtnCancel.setEnabled(true);
            jLabelInfo.setText("Uploading course from " + courseFolderFile.getAbsolutePath() + "... Please Wait!");
            oThread = new Thread(new Runnable() {

                public void run() {
                    try {
                        //TODO llamar al servicio web para obtener la direccion a la que subir el curso
                        UserPrefs prefs = EditorPrefs.getInstance();
                        String defaultRepository = prefs.getValue(EditorPrefs.DEFAULT_REPOSITORY);

                        String ftpAddress = "";
                        String ftpRelativePath = "";
                        String ftpUser = "";
                        String ftpPassword = "";
                        String courseId = "";
                        Vector<String> dataVector = null;
                        courseId = getCourseIdentifier(courseFolderFile);
                        try {
                            System.out.println("voy a llamar con defaultrepository " + defaultRepository);
                            dataVector = RepositoryClient.getInstance(defaultRepository).registerCourse(defaultRepository, courseId);
                        } catch (Exception ex) {
                            Logger.getLogger(UploadProgressPanel.class.getName()).log(Level.SEVERE, null, ex);
                        }

                        //Obtenemos los valores del dataVector
                        ftpAddress = dataVector.get(0);
                        ftpRelativePath = dataVector.get(1);
                        ftpUser = dataVector.get(2);
                        ftpPassword = dataVector.get(3);
                        courseId = dataVector.get(4);
                        System.out.println("courseFolderFile " + courseFolderFile + " ftpAddress " + ftpAddress + " ftpUser " + ftpUser + " ftpPassword " + ftpPassword + " ftpRelativePath " + ftpRelativePath);
                        //UploadTask upTask = new UploadTask(courseFolderFile, "193.146.210.128", "prueba", "prueba", "/course2/", jpbGlobal, jpbFile, jl, jl2, jLabelUploading);
                        UploadTask upTask = new UploadTask(courseFolderFile, ftpAddress, ftpUser, ftpPassword, ftpRelativePath, jpbGlobal, jpbFile, jl, jl2, jLabelUploading, defaultRepository);
                        //UploadTask upTask = new UploadTask(courseFolderFile, "10.100.60.232", "prueba", "prueba", "/courses/", jpbGlobal, jpbFile, jl, jLabelUploading);
                        upTask.execute();
                        //TODO llamar a endUpload
                        String courseUrl = "";

                        try {
                            RepositoryClient.getInstance(defaultRepository).endUpload(courseId, defaultRepository);
                            courseUrl = RepositoryClient.getInstance(defaultRepository).getCourseURL(courseId, defaultRepository);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                        if (defaultRepository.equals("Osami")) {
                            System.out.println("URL del curso que acabamos de subir: " + courseUrl);
                            //Creamos el manifest del bundle de metadatos
                            CourseManifestReader cmr = new CourseManifestReader(new File(courseFolderFile, "imsmanifest.xml"));
                            Manifest mf = new Manifest();
                            Attributes att = mf.getMainAttributes();
                            att.putValue("Manifest-Version", "1.0");
                            att.putValue("Bundle-ManifestVersion", "2");
                            att.putValue("Bundle-Name", "COURSE_" + courseId);
                            att.putValue("Bundle-SymbolicName", "COURSE_" + courseId);
                            att.putValue("Bundle-Version", "1.0.0");
                            att.putValue("Bundle-Description", cmr.getDescription());
                            att.putValue("Course-title", cmr.getTitle());
                            att.putValue("Course-url", courseUrl);
                            att.putValue("Course-icon", courseUrl + "/icon.jpg");
                            att.putValue("Course-category", "uncategorized");
                            //TODO crear el bundle de metadatos para subir al repositorio de bundles
                           File f= new File(courseFolderFile, "COURSE_" + courseId + ".jar");
                            try {
                                FileOutputStream fos = new FileOutputStream(f);
                                JarOutputStream jos = new JarOutputStream(fos, mf);
                                jos.closeEntry();
                                jos.close();
                                fos.close();
                                /*FileOutputStream fosMf = new FileOutputStream(new File(courseFolderFile, "Manifest.mf"));
                                mf.write(fosMf);
                                fosMf.close();*/

                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }

                            //TODO Subir el bundle de metadatos al repositorio
                            System.out.println("Resultado de subir el bundle al repositorio ");
                            System.out.println(BundleRepository.uploadMetadataBundle(f));
                            //TODO falta borrar el bundle de metadatos una vez subido al repositorio

                            if (f.delete()) {
                                System.out.println("El fichero ha sido borrado satisfactoriamente");
                            } else {
                                System.out.println("El fichero no puede ser borrado");
                            }
                        }

                        /*int numFilesToUpload = upTask.countFiles();
                        System.out.println("Numero de ficheros en el curso: " + numFilesToUpload);
                        File currentFile;
                        int currentFileNumber = 1;
                        long totalSize = upTask.getTotalSize();
                        int size = (int)totalSize;
                        System.out.println("Tamamño total: "+totalSize+ " bytes");

                        //jpbGlobal.setMaximum(numFilesToUpload);
                        jpbGlobal.setMaximum((int)totalSize);

                        //System.out.println("Tamaño total (int): "+size+" bytes");
                        //System.out.println("Entero más grande: "+Integer.MAX_VALUE);
                        //int num = Integer.MAX_VALUE;
                        //System.out.println("Entero más grande guardado en un int: "+num+" ("+Integer.SIZE+")");
                        while ((currentFile = upTask.nextFile()) != null) {
                        jLabelUploading.setText("Uploading: " + currentFile.getName());
                        Thread.sleep(100);
                        int percentage = (int) Math.floor((currentFileNumber * 100) / numFilesToUpload);

                        //jpbGlobal.setValue(percentage);
                        //jpbGlobal.setValue(currentFileNumber);
                        jpbGlobal.setValue(jpbGlobal.getValue()+(int)currentFile.length());

                        jl.setText(percentage + "%");
                        currentFileNumber++;
                        }*/
                        /*for (int i = 1; i <= 100; i++) {


                        //Do the upload thing!!!!
                        Thread.sleep(100);

                        jpb.setValue(i);
                        jl.setText(i + "%");
                        }*/
                        oBtnCancel.setEnabled(false);
                        jLabelInfo.setText("Upload completed sucessfully!");
                        jLabelUploading.setText("");
                        jl.setText("Done!");
                        jl2.setText("Done!");
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                        oBtnCancel.setEnabled(false);
                        jLabelInfo.setText("Upload canceled by the user!");
                        jLabelUploading.setText("");
                    }
                }
            });
            oThread.start();

        }
    }

    private String getCourseIdentifier(File file) {
        File mfFile = new File(file.getAbsolutePath() + "\\imsmanifest.xml");
        // System.out.println(mfFile.getAbsolutePath());
        SAXBuilder builder = new SAXBuilder(false);
        org.jdom.Document doc = null;
        try {
            doc = builder.build(mfFile);

        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (JDOMException ex) {
            ex.printStackTrace();
        }

        org.jdom.Element raiz = doc.getRootElement();
        org.jdom.Namespace manifestNS = raiz.getNamespace();
        org.jdom.Namespace metadataNS = raiz.getNamespace("imsmd");

        org.jdom.Element organizations = raiz.getChild("organizations", manifestNS);
        if (organizations != null) {
            org.jdom.Element organization = organizations.getChild("organization", manifestNS);
            if (organization != null) {
                //System.out.println(organization.getName());
                org.jdom.Element metadata = organization.getChild("metadata", manifestNS);
                if (metadata != null) {
                    //System.out.println(metadata.getName());
                    org.jdom.Element lom = metadata.getChild("lom", metadataNS);
                    if (lom != null) {
                        org.jdom.Element general = lom.getChild("general", metadataNS);
                        if (general != null) {
                            org.jdom.Element id = general.getChild("identifier", metadataNS);
                            if (id != null) {
                                String idText = id.getText();

                                System.out.println("Identifier " + idText);
                                if (idText != "") {
                                    return idText;
                                }
                            }
                        }
                    }
                }
            }
        }
        JOptionPane pane = new JOptionPane();
        pane.showMessageDialog((JPanel) this, "This course hasn´t identifier. Please, set an identifier at the metadata panel.", "Unable to upload", JOptionPane.INFORMATION_MESSAGE);
        if (oThread != null) {
            oThread.interrupt();
        }
        jpbGlobal.setEnabled(false);
        //jpb.setBackground(Color.GRAY);
        //jpb.setForeground(Color.GRAY);
        jl.setText("##%");
        oBtnCancel.setEnabled(false);
        jLabelInfo.setText("The user canceled the upload");

        return null;
    }

    public static void main(String args[]) {
        File mfFile = new File("C:\\documents and settings\\gonzalo\\escritorio\\curso_prueba\\imsmanifest.xml");
        SAXBuilder builder = new SAXBuilder(false);
        org.jdom.Document doc = null;
        try {
            doc = builder.build(mfFile);

        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (JDOMException ex) {
            ex.printStackTrace();
        }

        org.jdom.Element raiz = doc.getRootElement();
        org.jdom.Namespace manifestNS = raiz.getNamespace();
        org.jdom.Namespace metadataNS = raiz.getNamespace("imsmd");

        org.jdom.Element metadata = raiz.getChild("metadata", manifestNS);
        if (metadata != null) {
            org.jdom.Element lom = metadata.getChild("lom", metadataNS);
            if (lom != null) {
                org.jdom.Element general = lom.getChild("general", metadataNS);
                if (general != null) {
                    org.jdom.Element title = general.getChild("title", metadataNS);
                    org.jdom.Element description = general.getChild("description", metadataNS);

                    if (title != null) {
                        String titleText = title.getChild("langstring", metadataNS).getTextTrim();
                        System.out.println("Title: " + titleText);
                    } else {
                        System.out.println("no existe entrada para el título");
                    }
                    if (description != null) {
                        String descriptionText = description.getChild("langstring", metadataNS).getTextTrim();
                        System.out.println("Description: " + descriptionText);
                    } else {
                        System.out.println("no existe entrada para la descripcion");
                    }
                } else {
                    System.out.println("no existe entrada general");
                }
            } else {
                System.out.println("No existe entrada lom");
            }
        } else {
            System.out.println("No existen metadatos");
        }
    }
}
