package org.dbgl.preprocess;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.dbgl.db.Database;
import org.dbgl.model.DosboxVersion;
import org.dbgl.model.Profile;
import org.dbgl.model.SearchResult;
import org.dbgl.model.SearchResult.ResultType;
import org.dbgl.model.conf.Autoexec;
import org.dbgl.model.conf.Conf;
import org.dbgl.util.FileUtils;
import org.dbgl.util.PlatformUtils;


public class Repair {

	public static final class FileComparator implements Comparator<File> {
		public int compare(final File file1, final File file2) {
			String f1 = FilenameUtils.getBaseName(file1.getName());
			String f2 = FilenameUtils.getBaseName(file2.getName());
			try {
				int i1 = Integer.parseInt(f1);
				int i2 = Integer.parseInt(f2);
				return Integer.compare(i1, i2);
			} catch (NumberFormatException e) {
				return file1.getPath().compareToIgnoreCase(file2.getPath());
			}
		}
	}
	
	public static void main(String[] args) {
		System.out.println("Repairs broken DBGL installations (v0.2)\n");

		if (args.length < 1)
			displaySyntax();

		File inputDir = new File(args[0]);
		validateParameters(inputDir);

		System.out.println();

		List<DosboxVersion> dbversionsList = null;
		try {
			Database dbase = Database.getInstance();
			dbversionsList = dbase.readDosboxVersionsList();

			if (DosboxVersion.findDefault(dbversionsList) == null) {
				SearchResult result = PlatformUtils.findDosbox();
				if (result.result == ResultType.COMPLETE) {
					dbase.addOrEditDosboxVersion(result.dosbox.getTitle(), result.dosbox.getPath(), result.dosbox.getConf(), result.dosbox.isMultiConfig(), result.dosbox.isUsingCurses(),
						result.dosbox.isDefault(), result.dosbox.getParameters(), result.dosbox.getVersion(), result.dosbox.getId());
					dbversionsList = dbase.readDosboxVersionsList();
				}
				if (DosboxVersion.findDefault(dbversionsList) == null) {
					System.out.println("DOSBox installation could not be located, exiting.");
					System.exit(1);
				}
			}

			System.out.println("Using DOSBox installation located in: [" + DosboxVersion.findDefault(dbversionsList).getPath() + "]");
		} catch (SQLException e) {
			e.printStackTrace();
			System.exit(1);
		}

		List<Profile> profileList = analyzeExistingData(inputDir, dbversionsList);

		repairExistingData(profileList, inputDir, dbversionsList);
	}

	private static void displaySyntax() {
		System.out.println("Use: Repair <dbgldir>");
		System.exit(1);
	}

	private static void validateParameters(File inputDir) {
		if (!inputDir.exists()) {
			System.out.println("The directory [" + inputDir + "] does not exist, exiting.");
			System.exit(1);
		}
		File profilesDir = new File(inputDir, FileUtils.PROFILES_DIR);
		if (!profilesDir.exists()) {
			System.out.println("The directory [" + inputDir + "] does not contain the [" + FileUtils.PROFILES_DIR + "] directory, exiting.");
			System.exit(1);
		}
	}

	private static List<Profile> analyzeExistingData(File inputDir, List<DosboxVersion> dbversionsList) {
		System.out.println();
		System.out.println("===========================================");
		System.out.println(" Phase 1 of 2: Analyzing existing DBGL data");
		System.out.println("===========================================");
		System.out.println("Reading from: [" + inputDir + "]");

		PrintStream ps = new PrintStream(System.out);
		List<Profile> profileList = new ArrayList<Profile>();

		File profilesDir = new File(inputDir, FileUtils.PROFILES_DIR);
		File[] profileConfFiles = profilesDir.listFiles(new FileFilter() {
			public boolean accept(File file) {
				return file.isFile() && file.getName().toLowerCase().endsWith(".conf")
				&& !file.getName().equalsIgnoreCase(FileUtils.SETUP_CONF);
			}
		});
		Arrays.sort(profileConfFiles, new FileComparator());

		DosboxVersion dbversion = DosboxVersion.findDefault(dbversionsList);
		int dbversionId = dbversion.getId();
		String devName = StringUtils.EMPTY;
		String publName = StringUtils.EMPTY;
		String genre = StringUtils.EMPTY;
		String year = StringUtils.EMPTY;
		String status = StringUtils.EMPTY;
		String notes = StringUtils.EMPTY;
		boolean favorite = false;
		String[] setup = {"", "", ""};
		String[] setupParams = {"", "", ""};
		String[] links = {"", "", "", "", "", "", "", ""};
		String[] linkTitles = {"", "", "", "", "", "", "", ""};
		String[] customStrings = {"", "", "", "", "", "", "", "", "", "", "", ""};
		int[] customInts = {0, 0};
		
		for (int i = 0; i < profileConfFiles.length; i++) {
			try {
				Conf conf = new Conf(profileConfFiles[i], null, dbversion, ps);
				Autoexec autoexec = conf.getAutoexec();
				if (autoexec.isIncomplete()) {
					System.out.println("WARNING: " + profileConfFiles[i].getName() + ": This profile's autoexec section seems incomplete");
				}
				
				String name = FilenameUtils.getBaseName(profileConfFiles[i].getName());
				int nr;
				try {
					nr = Integer.parseInt(name);
				} catch (NumberFormatException e) {
					System.out.println("WARNING: " + profileConfFiles[i].getName() + ": Cannot determine associated captures folder");
					nr = -1;
				}
				
				String title = name + " " + autoexec.getActualMain();
				String confPathAndFile = FileUtils.getRelativePath(inputDir, profileConfFiles[i]);
				String captures = FileUtils.constructCapturesDir(nr);
				profileList.add(new Profile(nr, title, devName, publName, genre, year, status, notes, 
					favorite, setup, setupParams, confPathAndFile, captures, dbversionId, links, linkTitles,
						customStrings, customInts, null, null, null, null, 0, 0));
			} catch (IOException e) {
				System.out.println("SKIPPED " + profileConfFiles[i].getName() + " " + e.toString());
			}
		}

		System.out.println("Analysis done");
		return profileList;
	}

	private static void repairExistingData(List<Profile> profileList, File inputDir, List<DosboxVersion> dbversionsList) {
		System.out.println();
		System.out.println("===============================");
		System.out.println(" Phase 2 of 2: Repair DBGL data");
		System.out.println("===============================");

		Database dbase = Database.getInstance();
		for(Profile prof: profileList)
		{
			try {
				dbase.startTransaction();
				dbase.addProfileWithExplicitId(prof.getTitle(), prof.getDeveloperName(), prof.getPublisherName(), prof.getGenre(),
					prof.getYear(), prof.getStatus(), prof.getNotes(), prof.isDefault(), prof.getSetup(), prof.getSetupParameters(),
					prof.getDbversionId(), prof.getLinks(), prof.getLinkTitles(), prof.getCustomStrings(), prof.getCustomInts(), prof.getId());
				dbase.updateProfileConf(prof.getConfPathAndFile(), prof.getCaptures(), prof.getId());
				dbase.commitTransaction();
			} catch (SQLException e) {
				e.printStackTrace();
				try {
					dbase.rollbackTransaction();
				} catch (SQLException se) {
					se.printStackTrace();
				}
			} finally {
				dbase.finishTransaction();
			}
		}

		System.out.println("Finished.");
		try {
			dbase.shutdown();
		} catch (SQLException e) {
			// nothing we can do
		}
	}
}
