package org.postgresforest.tool.lib;

import java.sql.*;
import java.util.ArrayList;
import org.postgresforest.tool.Logger;
import org.postgresforest.tool.ArrayUtil;

public class TableUtils {

	/**
	 * テーブルに定義されている制約の定義用DDL文を作成する
	 *
	 * @param con データベースへのConnection
	 * @param schema スキーマ名
	 * @param relname テーブル名
	 *
	 * @return String[] 制約定義DDL文（ALTER TABLE ADD CONSTRAINT文）の配列
	 */
	public static String[] getConstraintDefs(Connection con,
											 String schema,
											 String relname)
		throws ForestToolException
	{
		return getConstraintDefs(con, schema, relname, relname);
	}

	/**
	 * テーブルに定義されている制約の定義用DDL文を作成する。
	 *
	 * 現在のテーブル名と別のテーブルに付加する制約を作成する場合には、
	 * newrelを指定する。
	 *
	 * @param con データベースへのConnection
	 * @param schema スキーマ名
	 * @param relname テーブル名
	 * @param newrel 制約を作成するテーブル名（新規テーブル名）
	 *
	 * @return String[] 制約定義DDL文（ALTER TABLE ADD CONSTRAINT文）の配列
	 */
	public static String[] getConstraintDefs(Connection con,
											 String schema,
											 String relname,
											 String newrel)
		throws ForestToolException
	{
		String sql = "SELECT c.conname, pg_get_constraintdef(c.oid) as condef " +
			         "  FROM pg_constraint c, pg_class r, pg_namespace n " +
			         " WHERE c.conrelid=r.oid " +
                     "   AND r.relname='" + relname + "' " +
                     "   AND r.relnamespace=n.oid " +
                     "   AND n.nspname='" + schema + "' " +
			         " ORDER BY conname";

        ArrayList a = new ArrayList();

        try {
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery(sql);

            while ( rs.next() )
            {
                String conname = rs.getString("conname");
                String condef  = rs.getString("condef");

				String def = null;

				def = "ALTER TABLE " + schema + "." + newrel + " ADD CONSTRAINT " + conname + " " + condef + ";";

				a.add(def);
            }

            rs.close();
            stmt.close();
        }
        catch (Exception e)
        {
            throw new ForestToolException(e);
        }

        return ArrayUtil.array2stringarray(a);
	}

	/**
	 * テーブルに定義されているインデックスの定義用DDL文を作成する。
	 * 主キー用インデックスは除く。
	 *
	 * @param con データベースへのConnection
	 * @param schema スキーマ名
	 * @param relname テーブル名
	 *
	 * @return String[] インデックス定義DDL文（CREATE INDEX文）の配列
	 */
	public static String[] getIndexDefs(Connection con,
										String schema,
										String relname)
		throws ForestToolException
	{
		return getIndexDefs(con, schema, relname, relname);
	}

	/**
	 * テーブルに定義されているインデックスの定義用DDL文を作成する。
	 * 主キー用インデックスは除く。
	 *
	 * 現在のテーブル名と別のテーブルに付加する制約を作成する場合には、
	 * newrelを指定する。
	 *
	 * @param con データベースへのConnection
	 * @param schema スキーマ名
	 * @param relname テーブル名
	 * @param newrel インデックスを作成するテーブル名（新規テーブル名）
	 *
	 * @return String[] 制約定義DDL文（CREATE INDEX文）の配列
	 */
	public static String[] getIndexDefs(Connection con,
										String schema,
										String relname,
										String newrel)
		throws ForestToolException
	{
        String sql = "SELECT pg_get_indexdef(r2.oid) as indexdef, r2.relname as indexname " +
			         "  FROM pg_namespace n, pg_class r, pg_class r2, pg_index i " +
                     " WHERE n.nspname='" + schema + "' " +
                     "   AND n.oid=r.relnamespace " +
                     "   AND r.relname='" + relname + "' " +
                     "   AND r.oid=i.indrelid " +
                     "   AND i.indexrelid=r2.oid" +
                     "   AND i.indisprimary=false";

        ArrayList a = new ArrayList();

        try {
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery(sql);

            while ( rs.next() )
            {
                String def  = rs.getString("indexdef") + ";";
                String name = rs.getString("indexname");

				Logger.debug("getIndexDefs: " + name + "=" + def);

				def = def.replaceAll(" ON " + relname, " ON " + newrel);

                a.add(def);
            }

            rs.close();
            stmt.close();
        }
        catch (Exception e)
        {
            throw new ForestToolException(e);
        }

        return ArrayUtil.array2stringarray(a);
	}

	public static String getSchemaName(String tableName)
	{
        if ( tableName.indexOf('.') > 0 )
            return tableName.substring( 0, tableName.indexOf('.') );

        return "public";
	}

	public static String getTableName(String tableName)
	{
		if ( tableName.indexOf('.') > 0 )
			return tableName.substring( tableName.indexOf('.')+1 );

		return tableName;
	}

}
