package industries.doublehelix.furrynotemanager;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;

import industries.doublehelix.conditionalfilter.filtertypes.container.MasterFilter;

public class Filters {
	public static String NO_FILTER_PLACEHOLDER = "(no filter)";
	
	public static Map<String, MasterFilter> getSavedFilters() throws SQLException {
		TreeSet<String> filtersToDelete = new TreeSet<String>();
		Map<String, MasterFilter> filters = new TreeMap<>();
		
		try (Statement s = DBTools.getInstance().getConnection().createStatement()) {
			try(ResultSet rs = s.executeQuery("SELECT * FROM FILTER")) {
				while(rs.next()) {
					String name = rs.getString("NAME");
					MasterFilter masterFilter = null;
					try {
						// this should have worked, but oh well
						//Object object = rs.getObject("SERIALIZEDFILTER");
						Object object = deserializeObject(rs.getBytes("SERIALIZEDFILTER"));
						masterFilter = (MasterFilter)object;
					} catch (Exception e) {
						// deserializingexception, classcastexception, ioexception, whatever
						e.printStackTrace();
						filtersToDelete.add(name);
						continue;
					}
					if (masterFilter == null) {
						filtersToDelete.add(name);
					} else {
						filters.put(name, masterFilter);
					}
				}
			}
		}
		
		// delete broken filters
		if (!filtersToDelete.isEmpty()) {
			// java.sql.SQLFeatureNotSupportedException: Feature not implemented: No details.
//			try (PreparedStatement ps = DBTools.getInstance().getConnection().prepareStatement("DELETE FROM FILTER WHERE NAME IN (?)")) {
//				Array array = DBTools.getInstance().getConnection().createArrayOf("VARCHAR", filtersToDelete.toArray());
//				ps.setArray(1, array);
//				ps.executeUpdate();
//			}
			
			for (String name : filtersToDelete) {
				deleteFilter(name);
			}
		}
		
		return filters;
	}
	
	public static MasterFilter getSavedFilter(String name) throws SQLException {
		boolean delete = false;
		
		try (PreparedStatement ps = DBTools.getInstance().getConnection().prepareStatement("SELECT * FROM FILTER WHERE NAME=?")) {
			ps.setString(1, name);
			try(ResultSet rs = ps.executeQuery()) {
				while(rs.next()) {
					MasterFilter masterFilter = null;
					try {
						// this should have worked, but oh well
						//Object object = rs.getObject("SERIALIZEDFILTER");
						Object object = deserializeObject(rs.getBytes("SERIALIZEDFILTER"));
						masterFilter = (MasterFilter)object;
					} catch (Exception e) {
						// deserializingexception, classcastexception, IOException, whatever
						e.printStackTrace();
						delete = true;
						continue;
					}
					if (masterFilter == null) {
						delete = true;
					} else {
						return masterFilter;
					}
				}
			}
		}
		
		// delete broken filter
		if (delete) deleteFilter(name);
		
		return null;
	}
	
	public static void deleteFilter(String name) throws SQLException {
		try (PreparedStatement ps = DBTools.getInstance().getConnection().prepareStatement("DELETE FROM FILTER WHERE NAME = ?")) {
			ps.setString(1, name);
			ps.executeUpdate();
		}
	}
	
	public static boolean saveFilter(String name, MasterFilter filter) throws SQLException, IOException {
		if (name == null || name.trim().isEmpty()) {
			System.err.println("Attempt to save filter with no name");
			return false;
		}
		if (name.equalsIgnoreCase(NO_FILTER_PLACEHOLDER)) {
			System.err.println("Attempt to save filter with name \"" + NO_FILTER_PLACEHOLDER + "\"");
			return false;
		}
		if (filter == null || filter.isEmpty()) {
			System.err.println("Attempt to save empty filter");
			return false;
		}
		StringBuffer sql = new StringBuffer();
		sql.append("INSERT INTO FILTER (");
		sql.append("NAME, SERIALIZEDFILTER");
		sql.append(") VALUES (");
		sql.append("?,    ?");
		sql.append(")");
		
		try (PreparedStatement ps = DBTools.getInstance().getConnection().prepareStatement(sql.toString())) {
			ps.setString(1, name.trim());
			
			// this should have worked, but oh well
			//ps.setObject(2, filter);
			ps.setBytes(2, serializeObject(filter));
			
			ps.executeUpdate();
		}
		return true;
	}
	
	public static boolean updateFilter(String name, MasterFilter filter) throws SQLException, IOException {
		if (name == null || name.trim().isEmpty()) {
			System.err.println("Attempt to update filter with no name");
			return false;
		}
		if (name.equalsIgnoreCase(NO_FILTER_PLACEHOLDER)) {
			System.err.println("Attempt to update filter with name \"" + NO_FILTER_PLACEHOLDER + "\"");
			return false;
		}
		if (filter == null || filter.isEmpty()) {
			System.err.println("Attempt to update empty filter");
			return false;
		}
		StringBuffer sql = new StringBuffer();
		sql.append("UPDATE FILTER ");
		sql.append("SET SERIALIZEDFILTER = ? ");
		sql.append("WHERE NAME=?");
		
		try (PreparedStatement ps = DBTools.getInstance().getConnection().prepareStatement(sql.toString())) {
			// this should have worked, but oh well
			//ps.setObject(1, filter);
			ps.setBytes(1, serializeObject(filter));
			ps.setString(2, name.trim());
			
			ps.executeUpdate();
		}
		return true;
	}
	
	private static byte[] serializeObject(Object o) throws IOException {
		byte[] bytes = null;
		try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
			try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
				oos.writeObject(o);
			}
			bytes = bos.toByteArray();
		}
		return bytes;
	}
	
	private static Object deserializeObject(byte[] bytes) throws ClassNotFoundException, IOException {
		Object o = null;
		try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes)) {
			try (ObjectInputStream ois = new ObjectInputStream(bis)) {
				o = ois.readObject();
			}
		}
		return o;
	}
}
