import org.apache.tika.config.TikaConfig;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.apache.tika.mime.MimeType;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import javax.swing.*;
import java.io.*;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class MyFiles {
    public class sortResult {
        public String           label;
        public ArrayList<Movie> movie;
        public sortResult(String lab) {
            label = lab;
            movie = new ArrayList<>();
        }
    }
    //--------------------------------------
    private static final Set<String> movadj = new HashSet<>(Arrays.asList(
            "240p", "360p", "480p", "720p", "1080p",
            "dvdrip", "brrip", "tvrip", "tsrip", "hdrip", "webrip",
            "cam", "tscam", "bluray", "dvd", "web", "web-dl",
            "hdtv", "hdtc", "dvdscreener", "vcd", "xvcd", "xvid",
            "x264", "h264", "aac", "ac3", "yify", "yts", "ag"
    ));
    private static TikaConfig   config;
    private MyVideos_GUI        gui;
    private JMenuBar            menuBar;
    private ArrayList<File>     folders;
    private ArrayList<Movie>    movies;
    private DBManager           DBman;
    //--------------------------------------
    private static String   clearName(String str, String con) {
        String input = str.toLowerCase();
        input = input.replaceAll("[(){}\\[\\]]", "");
        input = input.replaceAll("[':;,~]", "");
        String output = "";
        String[] tokens = input.split("[ ._-]");
        for (String tk : tokens) {
            if (!movadj.contains(tk)) {
                output += tk + con;
            }
        }
        return output;
    }
    private static String   getMovieUrl(File src) {
        String input = clearName(src.getName(), " ");
        if (!(input.contains("deleted scene")
                || input.contains("deletedscene")
                || input.contains("alternate ending")
                || input.contains("alternateending")
                || input.contains("deleted and extended scenes")
                || input.contains("deletedandextendedscenes")
                || input.contains("extended scenes")
                || input.contains("extendedscenes")
                || input.contains("extras")
                || getFileFolder(src).contains("extras"))) {
            return input.replaceAll(" ", "%20");
        } else return null;
    }
    private static MimeType getFileMime(File src) {
        try {
            BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(src));
            MediaType mediaType = config.getMimeRepository().detect(buffer, new Metadata());
            return config.getMimeRepository().forName(mediaType.toString());
        } catch (Exception ex) {
            return null;
        }
    }
    private static String   getFileExtension(File scr) {
        MimeType mime = getFileMime(scr);
        if (mime != null) return mime.getExtension();
        else return null;
    }
    private static String   getFileFolder(File scr) {
        String filePath = scr.getParent();
        int dotIndex = filePath.lastIndexOf(File.separatorChar);
        return (dotIndex == -1) ? "" : filePath.substring(dotIndex + 1);
    }
    private static boolean  isVideo(File scr) {
        MimeType mime = getFileMime(scr);
        return (mime != null)&&(mime.toString().contains("video"));
    }
    private Movie findMovieByID(int id) {
        for(Movie movie : movies){
            if(movie.getID() == id) return movie;
        }
        return null;
    }
    //--------------------------------------
    public MyFiles(DBManager db, MyVideos_GUI g) {
        gui     = g;
        DBman   = db;
        folders = new ArrayList<>();
        movies  = new ArrayList<>();
        config  = TikaConfig.getDefaultConfig();
    }
    //--------------------------------------
    public void addMenuBar(JMenuBar mb) {
        menuBar = mb;
    }
    public void addFolderMenuView(File folder) {
        // Archivos a mostras de carpetas cargadas con anterioridad
        JCheckBoxMenuItem cbMenuItem;
        cbMenuItem = new JCheckBoxMenuItem(folder.getName());
        cbMenuItem.setState(true);

        MenuViewListener mView = new MenuViewListener(this);
        cbMenuItem.addItemListener(mView);

        JMenu menuView = menuBar.getMenu(1);
        menuView.add(cbMenuItem);
    }
    public void addGrid(String s, ArrayList<Movie> mov) {
        gui.cleanGridPanels();
        gui.addGridPanel(s, mov);
        gui.revalidate();
    }
    public void addFolder(File folder) {
        folders.add(folder);
    }
    //--------------------------------------
    public void addFiles(File folder) {
        ArrayList<File> movieFiles = new ArrayList<>();
        ArrayList<File> directories = new ArrayList<>();
        File[] files = folder.listFiles();
        int index = 0;
        boolean isEnd = false;
        if (files != null) {
            addFolder(folder);
            while (!isEnd) {
                if (files.length != 0) {                     //Existen elementos en el directorio
                    for (File file:files) {
                        if (file.isFile()) {                 //Son archivos
                            if (isVideo(file)) movieFiles.add(file);
                        } else if (file.isDirectory()) {     //Son directorios
                            directories.add(file);
                        }
                    }
                }
                if (index < directories.size()) {            //Quedan directorios internos por revisar
                    files = (directories.get(index)).listFiles();
                    index++;
                } else isEnd = true;
            }
        } else if (folder.isFile()) {                        //Suponiendo que la entrada sea un archivo
            if (isVideo(folder)) movieFiles.add(folder);
        }
        addMoviesInfo(movieFiles);
        addGrid("All", movies);
    }
    //--------------------------------------
    public void addMoviesInfo(ArrayList<File> movieFiles) {
        ProgressMonitor progressMonitor = new ProgressMonitor(null, "Descargando Información", "",0,movies.size());
        progressMonitor.setProgress(0);
        System.out.println("Check for downloads...");
        if (movieFiles.size() > 0) {
            Movie   tempMovie;
            String  msgProgressAux;
            int     countProgressAux = 1;
            for (File movie : movieFiles) {
                System.out.print("Filename: "+movie.getName()+" | ");
                tempMovie = new Movie(movie, clearName(movie.getName(), " "), DBman);
                if(DBman.isMovie(tempMovie)) {
                    System.out.println("The movie already exists! Loading data from DB...");
                    DBman.getMovie(tempMovie);
                    movies.add(tempMovie);
                } else {
                    System.out.print("This is a new movie! Checking for url... ");
                    String urlB = getMovieUrl(movie);
                    String urlG = "http://www.google.com/search?q=IMDb%20" + urlB + "&btnI";
                    if (urlB != null) {
                        System.out.println(urlG);
                        boolean flag = true;
                        while (flag) {
                            try {
                                Document docu = Jsoup.connect(urlG).get();
                                if (docu != null) {
                                    String urlAux = docu.baseUri();
                                    if (urlAux.contains("imdb")) {
                                        urlG = urlAux;
                                        flag = false;
                                    } else if (urlB.length() > 1) {
                                        if (urlB.endsWith("%20")) {
                                            int index = urlB.lastIndexOf("%20");
                                            if (index != -1) urlB.substring(0, index);
                                        } else urlB = urlB.substring(0, urlB.length() - 1);
                                        urlG = "http://www.google.com/search?q=IMDb%20" + urlB + "&btnI";
                                    } else flag = false;
                                }
                            } catch (Exception ex) {
                                ex.printStackTrace();
                                flag = false;
                            }
                        }
                        if (urlG.length() > 36) urlG = urlG.substring(0, 36);
                        if (urlG.contains("http://www.imdb.com/title")){
                            tempMovie.setMovie(urlG);
                            movies.add(tempMovie);
                        } else {
                            movies.add(tempMovie);
                        }
                    } else {
                        System.out.println("Sorry, it's not possible to make the search!");
                    }
                }
                progressMonitor.setProgress(countProgressAux);
                msgProgressAux = String.format("%d de %d películas.\n", countProgressAux, movies.size());
                progressMonitor.setNote(msgProgressAux);
                countProgressAux++;
                if(progressMonitor.isCanceled())
                    break;
            }
        }
    }
    public ArrayList<sortResult> getMovieBy(String att) {
        att = att.toLowerCase();
        String query = null;
        boolean All = false;
        switch (att) {
            case "name": query =    "SELECT IDMOV,SUBSTRING(MNAME,1,1) AS ATTN "
                    +"FROM TBLMOVIE ORDER BY MNAME ASC"; break;
            case "year": query =    "SELECT IDMOV, MYEAR AS ATTN "
                    +"FROM TBLMOVIE ORDER BY ATTN ASC, MNAME ASC"; break;
            case "dir":  query =    "SELECT M.IDMOV AS IDMOV, D.ANAME AS ATTN "
                    +"FROM TBLMOVIE AS M "
                    +"INNER JOIN TBLDIRECTOR AS D ON (D.IDNUM = M.IDDIR) "
                    +"ORDER BY ATTN ASC, MNAME ASC"; break;
            case "gen":  query =    "SELECT M.IDMOV AS IDMOV, G.ANAME AS ATTN "
                    +"FROM TBLGENREMIX AS MX "
                    +"INNER JOIN TBLGENRE AS G ON (G.IDNUM = MX.IDATT) "
                    +"INNER JOIN TBLMOVIE   AS M ON (M.IDMOV = MX.IDMOV) "
                    +"ORDER BY ATTN ASC, M.MNAME ASC"; break;
            case "all": query = "SELECT IDMOV FROM TBLMOVIE ORDER BY MNAME ASC"; All = true; break;
        }
        try {
            String taux;
            ResultSet res;
            sortResult temp = new sortResult("");
            ArrayList<sortResult> sraux = new ArrayList<>();
            res = DBman.getStt().executeQuery(query);
            if (All) {
                temp.label = "All";
                while (res.next()) {
                    temp.movie.add(findMovieByID(res.getInt("IDMOV")));
                }
            } else {
                while (res.next()) {
                    taux = res.getString("ATTN");
                    if(taux != "") {
                        if(!temp.label.equals(taux)) {
                            sraux.add(temp);
                            temp = new sortResult(taux);
                        }
                        temp.movie.add(findMovieByID(res.getInt("IDMOV")));
                    }
                }
            }
            sraux.add(temp);
            return sraux;
        } catch (Exception ex) {
            return null;
        }
    }
    //--------------------------------------
    public ArrayList<File>  getFolders() {
        return folders;
    }
    public ArrayList<Movie> getMovies() {
        return movies;
    }
}