/*
 * App: Open Source software for novelists and authors.
 * Original idea 2008 - 2012 Martin Mustun
 * Copyrigth (C) Favdb
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
package storybook.model.oldmodel;

/**
 *
 * @author favdb
 */
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.h2.jdbc.JdbcSQLException;
import storybook.Const.STORYBOOK;
import storybook.model.oldmodel.MigrationConstants.ProjectSetting;
import storybook.tools.LOG;

//@Deprecated
public class InternalPeer {

	private static final String L_WHERE = " where ";
	private static final String L_FROM = " from ";

	private InternalPeer() {
		// empty
	}

	public static final String KEY_DB_MODEL_VERSION = "dbversion";

	public static void create() {
		try {
			createTable();
		} catch (Exception e) {
			LOG.err("InternalPeer.create()", e);
		}
	}

	public static void createTable() throws Exception {
		String sql;
		Statement stmt;
		// create
		//LOG.trace("InternalPeer.createTable(" + OldInternal.TABLE_NAME+")");
		sql = "create table IF NOT EXISTS "
				+ OldInternal.TABLE_NAME
				+ " ("
				+ OldInternal.COLUMN_ID + " identity primary key,"
				+ OldInternal.COLUMN_KEY + " varchar(512),"
				+ OldInternal.COLUMN_STRING_VALUE + " varchar(4096),"
				+ OldInternal.COLUMN_INTEGER_VALUE + " int,"
				+ OldInternal.COLUMN_BOOLEAN_VALUE + " binary(16384)"
				+ OldInternal.COLUMN_BIN_VALUE + " bool"
				+ ")";
		stmt = ModelMigration.getInstance().getConnection().createStatement();
		stmt.execute(sql);
	}

	public static List<OldInternal> doSelectAll() {
		try {
			if (!ModelMigration.getInstance().isConnectionOpen()) {
				return new ArrayList<>();
			}
			List<OldInternal> list = new ArrayList<>();
			StringBuilder sql = new StringBuilder("select * from " + OldInternal.TABLE_NAME);
			sql.append(" order by " + OldInternal.COLUMN_KEY);
			Statement stmt = ModelMigration.getInstance().getConnection().createStatement();
			try ( ResultSet rs = stmt.executeQuery(sql.toString())) {
				while (rs.next()) {
					OldInternal internal = makeInternal(rs);
					list.add(internal);
				}
			}
			return list;
		} catch (SQLException e) {
			LOG.err("InternalPeer.doSelectAll()", e);
		}
		return new ArrayList<>();
	}

	public static OldInternal doSelectById(int id) throws Exception {
		String sql = "select * from " + OldInternal.TABLE_NAME
				+ L_WHERE
				+ OldInternal.COLUMN_ID + " = ?";
		PreparedStatement stmt = ModelMigration.getInstance()
				.getConnection().prepareStatement(sql);
		stmt.setInt(1, id);
		OldInternal internal = null;
		try ( ResultSet rs = stmt.executeQuery()) {
			int c = 0;
			while (rs.next() && c < 2) {
				internal = makeInternal(rs);
				++c;
			}
			if (c == 0) {
				return null;
			}
			if (c > 1) {
				throw new Exception("more than one record found");
			}
		}
		return internal;
	}

	public static OldInternal doSelectByKey(ProjectSetting ps) throws Exception {
		return doSelectByKey(ps.toString());
	}

	public static OldInternal doSelectByKey(String key) throws Exception {
		String sql = "select * "
				+ "from " + OldInternal.TABLE_NAME
				+ L_WHERE + OldInternal.COLUMN_KEY + " = ?";
		PreparedStatement stmt = ModelMigration.getInstance()
				.getConnection().prepareStatement(sql);
		stmt.setString(1, key);
		OldInternal internal = null;
		try ( ResultSet rs = stmt.executeQuery()) {
			int c = 0;
			while (rs.next() && c < 2) {
				internal = makeInternal(rs);
				++c;
			}
			if (c == 0) {
				return null;
			}
			if (c > 1) {
				throw new Exception("more than one record found");
			}
		}
		return internal;
	}

	public static int doCount() {
		try {
			String sql = "select count(" + OldInternal.COLUMN_ID + ")"
					+ L_FROM
					+ OldInternal.TABLE_NAME;
			Statement stmt = ModelMigration.getInstance().getConnection()
					.createStatement();
			try ( ResultSet rs = stmt.executeQuery(sql)) {
				rs.next();
				return rs.getInt(1);
			}
		} catch (SQLException e) {
			LOG.err("InternalPeer.doCount()", e);
		}
		return 0;
	}

	private static OldInternal makeInternal(ResultSet rs) throws SQLException {
		OldInternal internal = new OldInternal(rs.getInt(OldInternal.COLUMN_ID));
		internal.setKey(rs.getString(OldInternal.COLUMN_KEY));
		internal.setStringValue(rs.getString(OldInternal.COLUMN_STRING_VALUE));
		internal.setIntegerValue(rs.getInt(OldInternal.COLUMN_INTEGER_VALUE));
		internal.setBooleanValue(rs.getBoolean(OldInternal.COLUMN_BOOLEAN_VALUE));
		return internal;
	}

	public static boolean doDelete(OldInternal internal) throws Exception {
		if (internal == null) {
			return false;
		}
		String sql = "delete"
				+ L_FROM + OldInternal.TABLE_NAME
				+ L_WHERE + OldInternal.COLUMN_ID + " = " + internal.getId();
		Statement stmt = ModelMigration.getInstance().getConnection().createStatement();
		stmt.execute(sql);
		return true;
	}

	public static String getDbModelVersion() {
		try {
			OldInternal dbModel = doSelectByKey(KEY_DB_MODEL_VERSION);
			if (dbModel == null) {
				return null;
			}
			return dbModel.getStringValue();
		} catch (JdbcSQLException e) {
			try {
				// try to get the value from an old DB model
				String sql = "select *" + L_FROM + OldInternal.TABLE_NAME
						+ L_WHERE + OldInternal.COLUMN_KEY + " = '"
						+ KEY_DB_MODEL_VERSION + "'";
				Statement stmt = ModelMigration.getInstance()
						.getConnection().createStatement();
				try ( ResultSet rs = stmt.executeQuery(sql)) {
					rs.next();
					return rs.getString(OldInternal.COLUMN_OLD_VALUE);
				}
			} catch (SQLException se) {
				LOG.err("InternalPeer.getDbModelVersion()", se);
				return null;
			}
		} catch (Exception e) {
			LOG.err("InternalPeer.getDbModelVersion()", e);
			return null;
		}
	}

	public static void setDbModelVersion() {
		setDbModelVersion(STORYBOOK.DB_VERSION.toString());
	}

	public static void setDbModelVersion(String version) {
		//LOG.trace("InternalPeer.setDbModelVersion(version=" + version + ")");
		try {
			OldInternal internal = doSelectByKey(KEY_DB_MODEL_VERSION);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(KEY_DB_MODEL_VERSION);
			}
			internal.setStringValue(version);
			internal.save();
			LOG.log(("setting DB version to " + version));
		} catch (Exception e) {
			LOG.err("InternalPeer.setDbModelVersion()", e);
		}
	}

	public static void setScaleFactorDefaults() {
		setScaleFactorBook(MigrationConstants.DEFAULT_SCALE_FACTOR_BOOK);
		setScaleFactorChrono(MigrationConstants.DEFAULT_SCALE_FACTOR_CHRONO);
		setScaleFactorManage(MigrationConstants.DEFAULT_SCALE_FACTOR_MANAGE);
	}

	public static void setScaleFactorChrono(int scaleFactor) {
		try {
			OldInternal internal = doSelectByKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_CHRONO);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_CHRONO);
			}
			internal.setIntegerValue(scaleFactor);
			internal.save();
		} catch (Exception e) {
			LOG.err("InternalPeer.setScaleFactorChrono(" + scaleFactor + ")", e);
		}
	}

	public static int getScaleFactorChrono() {
		try {
			OldInternal internal = doSelectByKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_CHRONO);
			if (internal == null) {
				return MigrationConstants.DEFAULT_SCALE_FACTOR_CHRONO;
			}
			return internal.getIntegerValue();
		} catch (Exception e) {
			LOG.err("InternalPeer.getScaleFactorChrono()", e);
		}
		return MigrationConstants.DEFAULT_SCALE_FACTOR_CHRONO;
	}

	public static void setScaleFactorBook(int scaleFactor) {
		try {
			OldInternal internal = doSelectByKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_BOOK);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_BOOK);
			}
			internal.setIntegerValue(scaleFactor);
			internal.save();
		} catch (Exception e) {
			LOG.err("InternalPeer.setScaleFactorChrono(" + scaleFactor + ")", e);
		}
	}

	public static int getScaleFactorBook() {
		try {
			OldInternal internal = doSelectByKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_BOOK);
			if (internal == null) {
				return MigrationConstants.DEFAULT_SCALE_FACTOR_BOOK;
			}
			return internal.getIntegerValue();
		} catch (Exception e) {
			LOG.err("InternalPeer.getScaleFactorChrono()", e);
		}
		return MigrationConstants.DEFAULT_SCALE_FACTOR_BOOK;
	}

	public static void setScaleFactorManage(int scaleFactor) {
		try {
			OldInternal internal = doSelectByKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_MANAGE);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_MANAGE);
			}
			internal.setIntegerValue(scaleFactor);
			internal.save();
		} catch (Exception e) {
			LOG.err("InternalPeer.setScaleFactorManage(" + scaleFactor + ")", e);
		}
	}

	public static int getScaleFactorManage() {
		try {
			OldInternal internal = doSelectByKey(MigrationConstants.ProjectSetting.SCALE_FACTOR_MANAGE);
			if (internal == null) {
				return MigrationConstants.DEFAULT_SCALE_FACTOR_MANAGE;
			}
			return internal.getIntegerValue();
		} catch (Exception e) {
			LOG.err("InternalPeer.getScaleFactorManage()", e);
		}
		return MigrationConstants.DEFAULT_SCALE_FACTOR_MANAGE;
	}

	public static void saveManageCols(int cols) {
		try {
			OldInternal internal = InternalPeer
					.doSelectByKey(MigrationConstants.ProjectSetting.MANAGE_VIEW_COLS);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(MigrationConstants.ProjectSetting.MANAGE_VIEW_COLS);
			}
			internal.setIntegerValue(cols);
			internal.save();
		} catch (Exception e) {
			LOG.err("InternalPeer.saveManaeGols(" + cols + ")", e);
		}
	}

	public static int getManageCols() {
		try {
			OldInternal internal = InternalPeer
					.doSelectByKey(MigrationConstants.ProjectSetting.MANAGE_VIEW_COLS);
			if (internal == null) {
				return 4;
			}
			return internal.getIntegerValue();
		} catch (Exception e) {
			LOG.err("InternalPeer.getManageCols()", e);
		}
		return 4;
	}

	public static void saveManageViewTextLength(int textLength) {
		try {
			OldInternal internal = InternalPeer
					.doSelectByKey(MigrationConstants.ProjectSetting.MANAGE_VIEW_TEXT_LENGTH);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(MigrationConstants.ProjectSetting.MANAGE_VIEW_TEXT_LENGTH);
			}
			internal.setIntegerValue(textLength);
			internal.save();
		} catch (Exception e) {
			LOG.err("InternalPeer.saveManageViewTextLength(" + textLength + ")", e);
		}
	}

	public static int getManageViewTextLength() {
		try {
			OldInternal internal = InternalPeer
					.doSelectByKey(MigrationConstants.ProjectSetting.MANAGE_VIEW_TEXT_LENGTH);
			if (internal == null) {
				return 100;
			}
			return internal.getIntegerValue();
		} catch (Exception e) {
			LOG.err("InternalPeer.getManageViewTextLength()", e);
		}
		return 100;
	}

	public static boolean getReadingView() {
		try {
			OldInternal internal = InternalPeer
					.doSelectByKey(MigrationConstants.ProjectSetting.READING_VIEW);
			if (internal == null) {
				// saveReadingView();
				return false;
			}
			return internal.getBooleanValue();
		} catch (Exception e) {
			LOG.err("InternalPeer.getReadingView()", e);
		}
		return false;
	}

	public static void saveReadingView(boolean readingView) {
		try {
			OldInternal internal = InternalPeer
					.doSelectByKey(MigrationConstants.ProjectSetting.READING_VIEW);
			if (internal == null) {
				internal = new OldInternal();
				internal.setKey(MigrationConstants.ProjectSetting.READING_VIEW);
			}
			internal.setBooleanValue(readingView);
			internal.save();
		} catch (Exception e) {
			LOG.err("InternalPeer.saveReadingView(" + (readingView ? "true" : "false") + ")", e);
		}
	}
}
