package lama.tablegen.sqlite3;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.sqlite.SQLiteException;

import lama.Randomly;
import lama.Main.StateToReproduce;
import lama.schema.Schema;
import lama.schema.Schema.Table;

// see https://www.sqlite.org/lang_dropindex.html
public class SQLite3DropIndexGenerator {

	private boolean sureItExists;

	public static void dropIndex(Connection con, StateToReproduce state, Schema s) throws SQLException {
		try (Statement stm = con.createStatement()) {
			SQLite3DropIndexGenerator gen = new SQLite3DropIndexGenerator();
			String query = gen.dropIndex(con, s);
			
			try {
				state.statements.add(query);
				stm.execute(query);
			} catch (SQLiteException e) {
				if (e.getMessage().startsWith(
						"[SQLITE_ERROR] SQL error or missing database (index associated with UNIQUE or PRIMARY KEY constraint cannot be dropped)")) {
					return;
				} else {
					throw new AssertionError(e);
				}
			}
		}
	}

	private String dropIndex(Connection con, Schema s) throws SQLException {
		Table randomTable = s.getRandomTable();
		List<String> indices = getIndexes(randomTable, con);
		String indexName = getRandomIndexName(indices);
		StringBuilder sb = new StringBuilder();
		sb.append("DROP INDEX ");
		if (!sureItExists || Randomly.getBoolean()) {
			sb.append("IF EXISTS ");
		}
		sb.append('"');
		sb.append(indexName);
		sb.append('"');
		return sb.toString();
	}

	private enum Options {
		KNOW_INDEX, // query from schema
		INDEX_LIKE, // string that looks like an index
		RANDOM_STRING
	}
	
	private String getRandomIndexName(List<String> indices) throws AssertionError {
		Options dropOption = Randomly.fromOptions(Options.values());
		while (true) {
			switch (dropOption) {
			case KNOW_INDEX:
				if (!indices.isEmpty()) {
					sureItExists = true;
					return Randomly.fromList(indices);
				}
				break;
			case INDEX_LIKE:
				return SQLite3Common.createIndexName(0);
			case RANDOM_STRING:
				return Randomly.getString();
			default:
				throw new AssertionError();
			}
		}
	}

	private static List<String> getIndexes(Table randomTable, Connection con) throws SQLException {
		try (Statement s = con.createStatement()) {
			ResultSet results = s.executeQuery("PRAGMA index_list(" + randomTable.getName() + ")");
			List<String> indices = new ArrayList<>();
			while (results.next()) {
				String index = results.getString(2);
				indices.add(index);
			}
			return indices;
		}
	}

}

@@ -193,66 +193,8 @@
 t;%0A%0A
-import org.sqlite.SQLiteException;%0A%0Aimport lama.Randomly;%0A
 impo
@@ -224,16 +224,38 @@
 roduce;%0A
+import lama.Randomly;%0A
 import l
@@ -306,16 +306,17 @@
 .Table;%0A
+ 
 %0A// see 
@@ -691,19 +691,16 @@
 on, s);%0A
-%09%09%09
 %0A%09%09%09try 
@@ -773,19 +773,16 @@
 tch (SQL
-ite
 Exceptio
@@ -1620,17 +1620,16 @@
 RING%0A%09%7D%0A
-%09
 %0A%09privat
@@ -1769,26 +1769,8 @@
 ));%0A
-%09%09while (true) %7B%0A%09
 %09%09sw
@@ -1791,17 +1791,16 @@
 on) %7B%0A%09%09
-%09
 case KNO
@@ -1808,17 +1808,16 @@
 _INDEX:%0A
-%09
 %09%09%09if (!
@@ -1833,25 +1833,24 @@
 sEmpty()) %7B%0A
-%09
 %09%09%09%09sureItEx
@@ -1862,25 +1862,24 @@
 = true;%0A%09%09%09%09
-%09
 return Rando
@@ -1905,26 +1905,58 @@
 s);%0A
-%09
 %09%09%09%7D
+ else %7B
 %0A%09%09%09%09
-b
 re
-ak;%0A%09
+turn Randomly.getString();%0A%09%09%09%7D%0A
 %09%09ca
@@ -1970,17 +1970,16 @@
 X_LIKE:%0A
-%09
 %09%09%09retur
@@ -2014,17 +2014,16 @@
 ame(0);%0A
-%09
 %09%09case R
@@ -2035,25 +2035,24 @@
 _STRING:%0A%09%09%09
-%09
 return Rando
@@ -2068,17 +2068,16 @@
 ring();%0A
-%09
 %09%09defaul
@@ -2082,17 +2082,16 @@
 ult:%0A%09%09%09
-%09
 throw ne
@@ -2110,21 +2110,16 @@
 rror();%0A
-%09%09%09%7D%0A
 %09%09%7D%0A%09%7D%0A%0A

Improve the dropping of indices