package honk.tools.anidb;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.plaf.basic.BasicBorders;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;


public class AniDB {

    public static enum Mode {
        PRETEND, IDENTIFY, MOVE
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        if (args.length < 1) {
            System.err.println("Usage: AniDB [pretend|move] <target folder> <source folders>");
            System.err.println("       AniDB identify <source folders>");
            System.exit(1);
        }
        String strMode = args[0];
        Mode mode;
        if (strMode.equals("pretend") && args.length >= 3) {
            mode = Mode.PRETEND;
        } else if (strMode.equals("identify") && args.length >= 2) {
            mode = Mode.IDENTIFY;
        } else if (strMode.equals("move") && args.length >= 3) {
            mode = Mode.MOVE;
        } else {
            System.err.println("Usage: AniDB [pretend|move] <target folder> <source folders>");
            System.err.println("       AniDB identify <source folders>");
            System.exit(1);
            return;
        }

        File target = new File(args[1]);
        File[] source = new File[args.length - 2];

        for (int i = 0; i < args.length - 2; i++) {
            source[i] = new File(args[i + 2]);
        }


        AniDBConnectionCache cache = DBFactory.createCache();
        if (cache == null) {
            System.err.println("Cannot initialise anidb cache.");
            System.exit(2);
        }

        AniDBConnection db = DBFactory.createConnecton();
        if (db == null) {
            System.err.println("Cannot initialise anidb connection.");
            System.exit(3);
        }

        AniDBConnection wrapper = DBFactory.createWrapper(db, cache);

        
        
       /* File f = new File("/home/honk/coding/test2.html");
        try {
            writeAniDBHtml(f, wrapper.getAnime(35));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.exit(0);*/
        
        
        
        try {
            switch (mode) {
                case IDENTIFY: {
                    File[] all = new File[1+source.length];
                    all[0] = target;
                    System.arraycopy(source, 0, all, 1, source.length);
                    
                    identify(all, wrapper);
                    break;
                }
                case PRETEND: {
                    pretend(source, target, wrapper);
                    break;
                }
                case MOVE: {
                    move(source, target, wrapper);
                    break;
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }

        System.exit(0);

    }


    /**
     * Recursively identifies all files in source.
     * Moves each file to "target/anime[kanji]/anime[preferedName] - file[episodeNumber] - file[episodeName].file[fileType]"
     * Creates/moves an anidb for each file.
     * Creates an anidb file for each anime.
     * @param reallyMove if true, files will be moved, otherwise nothing will be done (output only)
     * @param source the source from which files should be moved and/or renamed
     * @param target the target to which the files should be moved (may be the same as source)
     * @param wrapper the AniDBConnection to use (should be cached)
     */
    private static void move(boolean reallyMove, File[] source, File target, AniDBConnection wrapper) {
        identify(source, wrapper);


        //TODO console version
        JFrame frame = new JFrame();

        JPanel panel = new JPanel();

        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints cLabel = new GridBagConstraints();
        cLabel.fill = GridBagConstraints.BOTH;
        cLabel.weightx = 0;
        GridBagConstraints cBox = new GridBagConstraints();
        cBox.weightx = 1;
        cBox.gridwidth = GridBagConstraints.REMAINDER; //end row
        cBox.fill = GridBagConstraints.BOTH;


        panel.setLayout(gridbag);

        Font unifont = null;
        try {
            unifont = Font.createFont(Font.TRUETYPE_FONT, new File("unifont.ttf"));
            unifont = unifont.deriveFont(16f);
        } catch (Exception e) {
            e.printStackTrace();
        }

        List<JComboBox> boxes = new ArrayList<JComboBox>();

        List<Integer> anime = wrapper.getAnimes();
        for (int aid : anime) {
            AnimeInfo animeInfo = wrapper.getAnime(aid);


            JLabel label = new JLabel(animeInfo.getRomajiName() + " ");
            panel.add(label, cLabel);
            label.setBorder(new BasicBorders.MarginBorder());

            if (animeInfo.getPreferedName() == null) {
                label.setBackground(Color.RED);
                label.setOpaque(true);
            }


            List<String> names = new ArrayList<String>();
            names.add(animeInfo.getRomajiName());
            if (animeInfo.getKanjiName().length() != 0) {
                names.add(animeInfo.getKanjiName());
            }
            if (animeInfo.getEnglishName().length() != 0) {
                names.add(animeInfo.getEnglishName());
            }
            for (String shortName : animeInfo.getShortNameList()) {
                names.add(shortName);
            }

            JComboBox box = new JComboBox(names.toArray());
            if (animeInfo.getPreferedName() != null) {
                int index = names.indexOf(animeInfo.getPreferedName());
                if (index >= 0) {
                    box.setSelectedIndex(names.indexOf(animeInfo.getPreferedName()));
                }
            }
            box.setFont(unifont);
            box.putClientProperty("AnimeInfo", animeInfo);

            boxes.add(box);


            panel.add(box, cBox);
        }


        JScrollPane jsp = new JScrollPane(panel);
        frame.add(jsp);
        frame.setSize(1024, 768);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        while (frame.isVisible()) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


        for (JComboBox box : boxes) {
            AnimeInfo ai = (AnimeInfo) box.getClientProperty("AnimeInfo");
            int aid = ai.getAnimeID();
            String newName = (String) box.getSelectedItem();
            String oldName = ai.getPreferedName();
            if (oldName == null || !oldName.equals(newName)) {
                wrapper.changePreferedName(aid, newName);
            }
        }

        for (File file : source) {
            move(reallyMove, file, target, wrapper);
        }
        // for each file:

        //   move file to target/anime.kanji/anime.preferedName - file.episodeNumber - file.episodeName
        //   move anidb to same spot
        // for each anime in files:
        //   create target/anime/anidb/name
    }


    private static void move(boolean reallyMove, File file, File target, AniDBConnection wrapper) {
        if (isAnidbFile(file)) {
            //ignore anidb files for obvious reasons :P
            return;
        }
        
        if (!file.exists()) {
            return;
        }

        if (file.canRead()) {
            if (file.isDirectory()) {
                System.out.println("entering   " + file);
                for (File child : file.listFiles()) {
                    move(reallyMove, child, target, wrapper);
                }
                if (file.exists() && file.listFiles().length == 0) {
                    file.delete();
                } else if (file.exists() && file.listFiles().length == 1) {
                    File subFile = file.listFiles()[0];
                    if (subFile.isDirectory() && subFile.listFiles().length == 0) {
                        subFile.delete();
                        file.delete(); 
                    }
                }
            } else {
                File anidbFile = new File(getAnidbPath(file));
                if (!anidbFile.exists()) {
                    return;
                }
                
                try {
                    FileInfo fi = readAniDBFileInfo(anidbFile);
                    
                    //cached unknown
                    if (fi == null) {
                        return;
                    }

                    String newName = getNewName(target, fi, wrapper);
                    if (newName != null) {
                        File newFile = new File(newName);
                        File newAnidbFile = new File(getAnidbPath(newFile));
                        File folder = newFile.getParentFile();

                        if (reallyMove) {
                            AnimeInfo ai = wrapper.getAnime(fi.getAnimeID());


                            //write animeinfo no matter if file is ok or not
                            File anidbAnimeFile = new File(getAnidbPath(folder, getAnimeName(ai)));
                            if (!anidbAnimeFile.exists()) {
                                writeAniDB(anidbAnimeFile, ai);
                            }
                            
                            File anidbAnimeHtmlFile = new File(getAnidbFolder(folder) + getAnimeName(ai)+".html");
                            if (!anidbAnimeHtmlFile.exists()) {
                                writeAniDBHtml(anidbAnimeHtmlFile, ai);
                                
                                //also copy the images after creating the html file
                                File pictureFile = new File("images" + File.separator + ai.getPicName());
                                String picEnding = ai.getPicName().replaceFirst(".*\\.", "");
                                File newPictureFile = new File(getAnidbPath(folder, getAnimeName(ai), picEnding));
                                if (pictureFile.exists() && !newPictureFile.exists()) {
                                    FileUtils.copyFile(pictureFile, newPictureFile);
                                }
                                
                                
                                
                                File relationsPictureFile = new File("images" + File.separator + "relations" + File.separator + ai.getAnimeID() +".png");
                                File newRelationsPictureFile = new File(getAnidbPath(folder, getAnimeName(ai)+"-relations", "png"));
                                if (relationsPictureFile.exists() && !newRelationsPictureFile.exists()) {
                                    FileUtils.copyFile(relationsPictureFile, newRelationsPictureFile);
                                }
                            }

                            
                            
                            if (newFile.equals(file)) {
                                return;
                            }
                        

                            if (!folder.exists()) {
                                if (!folder.mkdirs()) {
                                    System.err.println("Error creating " + folder);
                                    System.err.println("  not moving " + file);
                                    return;
                                }
                            }


                            if (!file.renameTo(newFile)) {
                                FileUtils.copyFile(file, newFile);
                                file.delete();
                            }
                            if (!anidbFile.renameTo(newAnidbFile)) {
                                FileUtils.copyFile(anidbFile, newAnidbFile);
                                anidbFile.delete();
                            }
                            
                            if (anidbFile.getParentFile().listFiles().length == 0) {
                                anidbFile.getParentFile().delete();
                            }
                            
                            if (file.getParentFile().listFiles().length == 0) {
                                file.getParentFile().delete();
                            }
                        } else {
                            if (newFile.equals(file)) {
                                return;
                            }
                            
                            System.out.println("Move " + file);
                            System.out.println("  to " + newFile);
                            System.out.println("Move " + anidbFile);
                            System.out.println("  to " + newAnidbFile);
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }

    }

    
    private static String getAnimeName(AnimeInfo ai) {
        String animeTitle = ai.getRomajiName();
        animeTitle = animeTitle.replace('`', '\'');
        animeTitle = animeTitle.replace(File.separatorChar, '|');
        return animeTitle;
    }
    
    private static String getNewName(File target, FileInfo fi, AniDBConnection wrapper) {
        AnimeInfo ai = wrapper.getAnime(fi.getAnimeID());
        if (ai == null) {
            return null;
        }

        String newName = target.getAbsolutePath();
        newName += File.separatorChar;
        String animeTitle = getAnimeName(ai);
        newName += animeTitle;
        newName += File.separatorChar;
        
        String episodeTitle = fi.getEpisodeName();
        episodeTitle = episodeTitle.substring(0, Math.min(100, episodeTitle.length()));
        
        String episodeName = ai.getPreferedName() + " - " + fi.getEpisodeNumber() + " - " + episodeTitle + "."
                + fi.getFileType();
        episodeName = episodeName.replace('`', '\'');
        episodeName = episodeName.replace(File.separatorChar, '|');
        newName += episodeName;
        return newName;
    }


    /**
     * Same as move(true, source, target, wrapper)
     * @param source the source from which files should be moved and/or renamed
     * @param target the target to which the files should be moved (may be the same as source)
     * @param wrapper the AniDBConnection to use (should be cached)
     */
    private static void move(File[] source, File target, AniDBConnection wrapper) {
        move(true, source, target, wrapper);
    }

    /**
     * Same as move(false, source, target, wrapper)
     * @param source the source from which files should be moved and/or renamed
     * @param target the target to which the files should be moved (may be the same as source)
     * @param wrapper the AniDBConnection to use (should be cached)
     */
    private static void pretend(File[] source, File target, AniDBConnection wrapper) {
        move(false, source, target, wrapper);
    }

    /**
     * Recursively scans through a list of directories and identifies each file (creates an anidb file for each file).
     * @param source the animes to scan
     * @param wrapper the AniDBConnection to use (should be cached)
     */
    private static void identify(File[] source, AniDBConnection wrapper) {
        Set<File> validAniDBFiles = new HashSet<File>();
        identify(source, wrapper, validAniDBFiles);

        removeOldAnidb(source, validAniDBFiles);


        System.out.println("Getting pictures.");
        List<Integer> anime = wrapper.getAnimes();
        for (int aid : anime) {
            AnimeInfo animeInfo = wrapper.getAnime(aid);
            String picName = animeInfo.getPicName();
            File f = new File("images" + File.separator + picName);
            if (!f.exists()) {
                System.out.println("Retreiving " + "http://img5.anidb.info/pics/anime/" + picName);

                try {
                    FileUtils.copyURLToFile(new URL("http://img5.anidb.info/pics/anime/" + picName), f);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
               
            }
            
            
            File relFile = new File("images"+ File.separator+"relations"+File.separator+aid+".png");
            if (!relFile.exists() && !"".equals(animeInfo.getRelations())) {
                try {
                    FileUtils.copyURLToFile(new URL("http://anidb.info/pics/graph/a-"+aid+".png"), relFile); 
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("Getting pictures finished.");
    }


    /**
     * Recursively traverses the given folders and removes all anidb files that are not in the list of valid files.
     * @param source the folders to traverse (or files to check)
     * @param validAniDBFiles the files that should not be deleted
     */
    private static void removeOldAnidb(File[] source, Set<File> validAniDBFiles) {
        for (File f : source) {
            if (f.canRead()) {
                if (f.isDirectory()) {
                    System.out.println("entering   " + f);
                    removeOldAnidb(f.listFiles(), validAniDBFiles);
                    //try to remove empty directory
                    f.delete();
                } else if (isAnidbFile(f)) {
                    if (!validAniDBFiles.contains(f)) {
                        System.out.println("Removing stale anidb file: " + f);
                        //f.delete();
                        System.out.println("disabled");
                        //FIXME implement properly
                    }
                }
            }
        }
    }


    /**
     * Recursively scans through a list of directories and identifies each file (creates an anidb file for each file).
     * @param source the animes to scan
     * @param wrapper the AniDBConnection to use (should be cached)
     * @param validAniDBFiles a list that will be filled with valid anidb files
     */
    private static void identify(File[] source, AniDBConnection wrapper, Set<File> validAniDBFiles) {
        for (File f : source) {
            if (f.canRead()) {
                if (isAnidbFile(f)) {
                    continue;
                }
                
                if (f.isDirectory()) {
                    System.out.println("entering   " + f);
                    identify(f.listFiles(), wrapper, validAniDBFiles);
                } else {
                    identify(f, wrapper, validAniDBFiles);
                }
            }
        }
    }

    /**
     * Identifies the given file (creates an anidb file).
     * @param source a file to identify
     * @param wrapper the AniDBConnection to use (should be cached)
     */
    private static void identify(File f, AniDBConnection wrapper, Set<File> validAniDBFiles) {
        if (isAnidbFile(f)) {
            //ignore anidb files
            return;
        }
        if (f.length() < 10240) {
            //ignore files smaller than 10kb
            return;
        }

        System.out.print("processing " + f);


        File anidbFile = new File(getAnidbPath(f));
        if (anidbFile.canRead()) {
            try {
                FileInfo fileInfo = readAniDBFileInfo(anidbFile);
                System.out.println(" (cached)");
                validAniDBFiles.add(anidbFile);

                //cached unknown file
                if (fileInfo != null) {
                    wrapper.getAnime(fileInfo.getAnimeID());
                }
                return;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            System.out.print(" (searching..");
            int size = (int) f.length();
            String hash = Hasher.hash(f);
            FileInfo fileInfo = wrapper.getFile(size, hash);
            if (fileInfo != null) {
                System.out.print(". found..");
                writeAniDB(anidbFile, fileInfo);
                System.out.println(". written)");
                validAniDBFiles.add(anidbFile);

                wrapper.getAnime(fileInfo.getAnimeID());
            } else {
                System.out.println(". not found)");
                //cache non-hit
                anidbFile.getParentFile().mkdir();
                anidbFile.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(". failed)");
        }
    }
    
    
    /**
     * Returns the anidb file for the given file.
     * @param file the file
     * @return the anidb file
     */
    private static String getAnidbPath(File file) {
        String parent = file.getParentFile().getAbsolutePath();
        String fileName = file.getAbsolutePath().substring(parent.length());
        return parent + File.separatorChar + "anidb" + File.separatorChar + fileName + ".txt";
    }
    
    /**
     * Returns the anidb file for the given directory and name and .txt file ending.
     * @param file the directory
     * @param name the filename
     * @return the anidb file
     */
    private static String getAnidbPath(File file, String name) {
        return getAnidbPath(file, name, "txt");
    }
    
    /**
     * Returns the anidb file for the given directory and name and file ending
     * @param file the directory
     * @param name the filename
     * @param ext the file extension
     * @return the anidb file
     */
    private static String getAnidbPath(File file, String name, String ext) {
        return file.getAbsolutePath() + File.separatorChar + "anidb" + File.separatorChar + name + "."+ ext;
    }
    
    /**
     * Returns the anidb folder for the given directory.
     * @param file the directory
     * @return the anidb folder
     */
    private static String getAnidbFolder(File file) {
        return file.getAbsolutePath() + File.separatorChar + "anidb" + File.separatorChar;
    }

    /**
     * Returns true if the file is an anidb file
     * @param file the file to check
     * @return true if the file is an anidb file
     */
    private static boolean isAnidbFile(File file) {
        return file.getAbsolutePath().contains(File.separatorChar+"anidb"+File.separatorChar);
    }
    

    /**
     * Writes the given FileInfo into a file f.getAbsolutePath(). This method will overwrite any existing file without prior checks. 
     * @param anidbFile the file into which the info is written
     * @param fileInfo the info to write
     * @throws IOException if an error occurs writing the file
     */
    private static void writeAniDB(File anidbFile, FileInfo fileInfo) throws IOException {
        Properties props = new Properties() {
            private static final long serialVersionUID = -644386531792695142L;

            @Override
            public synchronized Object put(Object key, Object value) {
                if (!(value instanceof String)) {
                    value = value.toString();
                }
                return super.put(key, value);
            }
        };

        props.put("size", fileInfo.getSize());
        props.put("hash", fileInfo.getHash());
        props.put("animeID", fileInfo.getAnimeID());
        props.put("fileID", fileInfo.getFileID());
        props.put("episodeNumber", fileInfo.getEpisodeNumber());
        props.put("episodeName", fileInfo.getEpisodeName());
        props.put("description", fileInfo.getDescription());
        props.put("quality", fileInfo.getQuality());
        props.put("subLang", fileInfo.getSubLang());
        props.put("dubLang", fileInfo.getDubLang());
        props.put("length", fileInfo.getLength());
        props.put("fileType", fileInfo.getFileType());
        props.put("source", fileInfo.getSource());


        if (!anidbFile.getParentFile().exists()) {
            anidbFile.getParentFile().mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(anidbFile);
        props.store(fos, "File Info");
    }

    /**
     * Writes the given AnimeInfo into a file f.getAbsolutePath(). This method will overwrite any existing file without prior checks. 
     * @param anidbFile the file into which the info is written
     * @param animeInfo the info to write
     * @throws IOException if an error occurs writing the file
     */
    private static void writeAniDB(File anidbFile, AnimeInfo animeInfo) throws IOException {
        Properties props = new Properties() {
            private static final long serialVersionUID = -644386531792695142L;

            @Override
            public synchronized Object put(Object key, Object value) {
                if (value == null) {
                    value = "";
                }
                if (!(value instanceof String)) {
                    value = value.toString();
                }
                return super.put(key, value);
            }
        };


        props.put("animeID", animeInfo.getAnimeID());
        props.put("episodes", animeInfo.getEpisodes());
        props.put("normalEpisodes", animeInfo.getNormalEpisodes());
        props.put("specialEpisodes", animeInfo.getSpecialEpisodes());
        props.put("rating", animeInfo.getRating());
        props.put("voteCount", animeInfo.getVoteCount());
        props.put("tempRating", animeInfo.getTempRating());
        props.put("tempVoteCount", animeInfo.getTempVoteCount());
        props.put("picName", animeInfo.getPicName());
        props.put("year", animeInfo.getYear());
        props.put("type", animeInfo.getType());
        if (animeInfo.getPreferedName() != null) {
            props.put("preferedName", animeInfo.getPreferedName());
        }
        props.put("romajiName", animeInfo.getRomajiName());
        props.put("kanjiName", animeInfo.getKanjiName());
        props.put("englishName", animeInfo.getEnglishName());
        props
                .put("shortNameList", AnimeInfo.arrayToString(animeInfo.getShortNameList(),
                        AnimeInfo.SEPERATOR_SHORTNAME));
        props.put("categoryList", AnimeInfo.arrayToString(animeInfo.getCategoryList(), AnimeInfo.SEPERATOR_CATEGORY));
        props.put("description", animeInfo.getDescription());
        props.put("relations", animeInfo.getRelations());
        
        if (!anidbFile.getParentFile().exists()) {
            anidbFile.getParentFile().mkdirs();
        }
        FileOutputStream fos = new FileOutputStream(anidbFile);
        String comment = animeInfo.getRomajiName()+"\n#"+animeInfo.getDescription();
        props.store(fos, comment);
        fos.close();
    }
    
    
    /**
     * Writes the given AnimeInfo into a file f.getAbsolutePath(). This method will overwrite any existing file without prior checks. 
     * @param anidbFile the file into which the info is written
     * @param animeInfo the info to write
     * @throws IOException if an error occurs writing the file
     */
    private static void writeAniDBHtml(File anidbFile, AnimeInfo animeInfo) throws IOException {
        String html = "<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"><TITLE>"+animeInfo.getRomajiName()+"</TITLE></HEAD><BODY>";
        html += "<h1>"+animeInfo.getRomajiName()+"</h1>";
        
        String picEnding = animeInfo.getPicName().replaceFirst(".*\\.", "");
        String animeTitle = getAnimeName(animeInfo);
        File newPictureFile = new File(getAnidbPath(new File("."), animeTitle, picEnding));
        html += "<img src=\""+newPictureFile.getName()+"\" border=0><br>";

        
        html += animeInfo.getKanjiName()+"<br>";
        if (animeInfo.getEnglishName() != null && animeInfo.getEnglishName().length() != 0) {
            html += animeInfo.getEnglishName()+"<br>";
        }

        for (String shortName: animeInfo.getShortNameList()) {
            html += shortName+"<br>";
        }
        
        html += "<h2>Description</h2>";
        html += animeInfo.getDescription()+"<br>";
        
        html += "<h2>Categories</h2>";
        for (String category: animeInfo.getCategoryList()) {
            html += category+"<br>";
        }

        
        html += "<h2>Rating</h2>";
        html += "rating: "+animeInfo.getRating()/100f+"<br>";
        html += "votes: "+animeInfo.getVoteCount()+"<br>";
        html += "<h4>Unfinished Rating</h4>";
        html += "temp-rating: "+animeInfo.getTempRating()/100f+"<br>";
        html += "temp-votes: "+animeInfo.getTempVoteCount()+"<br>";
        
        
        html += "<h2>Episodes</h2>";
        html += "overall: "+animeInfo.getEpisodes()+"<br>";
        html += "normal: "+animeInfo.getNormalEpisodes()+"<br>";
        html += "special: "+animeInfo.getSpecialEpisodes()+"<br>";
        
        if (animeInfo.getRelations().length() != 0) {
            html += "<h2>Relations</h2>";
            File relationsPictureFile = new File(getAnidbPath(new File("."), animeTitle+"-relations", "png"));
            
            html += "<img src=\""+relationsPictureFile.getName()+"\" border=0><br>";
        }
        
        html += "</BODY></HTML>";
        
        
        FileOutputStream fos = new FileOutputStream(anidbFile);
        IOUtils.write(html, fos);
        fos.close();
    }



    /**
     * Returns the file information that is in the given file.
     * @param anidbFile the file to read
     * @return the information read from the given file
     * @throws IllegalFormatException if the file format is not correct
     * @throws IOException if an error occurs reading the file
     */
    private static FileInfo readAniDBFileInfo(File anidbFile) throws IllegalFormatException, IOException {
        if (anidbFile.length() == 0) {
            return null;
        }
        
        Properties props = new Properties();
        FileInputStream fis = new FileInputStream(anidbFile);
        props.load(fis);


        String[] values = { "size", "hash", "animeID", "fileID", "episodeNumber", "episodeName", "description",
                "quality", "subLang", "dubLang", "length", "fileType", "source" };
        for (String value : values) {
            if (props.get(value) == null) {
                throw new IllegalFormatException("No \"" + value + "\" attribute in " + anidbFile);
            }
        }
        try {
            int size = Integer.parseInt((String) props.get("size"));
            String hash = (String) props.get("hash");
            int animeID = Integer.parseInt((String) props.get("animeID"));
            int fileID = Integer.parseInt((String) props.get("fileID"));
            String episodeNumber = (String) props.get("episodeNumber");
            String episodeName = (String) props.get("episodeName");
            String description = (String) props.get("description");
            String quality = (String) props.get("quality");
            String subLang = (String) props.get("subLang");
            String dubLang = (String) props.get("dubLang");
            int length = Integer.parseInt((String) props.get("length"));
            String fileType = (String) props.get("fileType");
            String source = (String) props.get("source");


            return new FileInfo(size, hash, animeID, fileID, episodeNumber, episodeName, description, quality, subLang,
                    dubLang, length, fileType, source);
        } catch (NumberFormatException nfe) {
            throw new IllegalFormatException("Not a number in " + anidbFile, nfe);
        }
    }

}
