package net.northking.cctp.maven.analyse.entity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库表对象
 *
 * @author 谢秀松
 * @since 1.0
 */
public final class TableRef
{
  /**
   * 列/字段集合
   */
  private List<ColumnRef> columns = new ArrayList<ColumnRef>();
  private Map<String, ColumnRef> columnRefMap = new HashMap<>();

  /**
   * 表名
   */
  private String tableName;
  /**
   * 注释
   */
  private String comment;

  /**
   * catalog
   */
  private String catalog;

  /**
   * schema
   */
  private String schema;

  /**
   * 类型：表/视图
   */
  private String tableType;

  /**
   * 主键
   */
  private PrimaryKeyRef primaryKey;

  /**
   * 外键引用集合
   */
  private List<ForeignKeyRef> foreignKeys = new ArrayList<ForeignKeyRef>();

  /**
   * 外键Map
   */
  private Map<String, ForeignKeyRef> fkMap = new HashMap<>();

  /**
   * 索引集合
   */
  private List<IndexInfoRef> indexInfoRefs = new ArrayList<>();

  /**
   * 默认构造函数
   */
  public TableRef()
  {
  }

  /**
   * 构造函数
   *
   * @param tableCat   tableCat
   * @param tableSchem tableSchem
   * @param tableName  tableName
   * @param tableType  tableType
   * @param remarks    remarks
   */
  public TableRef(final String tableCat, final String tableSchem, final String tableName, final String tableType, final String remarks)
  {
    this.catalog = tableCat;
    this.schema = tableSchem;
    this.tableName = tableName;
    this.tableType = tableType;
    this.comment = remarks;
  }

  /**
   * 添加外键引用
   *
   * @param foreignKeyRefs 外键集合
   */
  public void addForeignKeys(final List<ForeignKeyRef> foreignKeyRefs)
  {
    for (ForeignKeyRef foreignKeyRef : foreignKeyRefs)
    {
      this.addForeignKey(foreignKeyRef);
    }
  }

  /**
   * 添加外键
   *
   * @param foreignKeyRef 外键
   */
  public void addForeignKey(final ForeignKeyRef foreignKeyRef)
  {
    ForeignKeyRef fk = fkMap.get(foreignKeyRef.getFkColumnName());
    if (fk == null)
    {
      fkMap.put(foreignKeyRef.getFkColumnName(), foreignKeyRef);
      this.foreignKeys.add(foreignKeyRef);
    } else
    {
      fk.setPkTableName(foreignKeyRef.getPkTableName());
      fk.setPkColumnName(foreignKeyRef.getPkColumnName());
    }
  }

  /**
   * 获取所有的列/字段
   *
   * @return 所有的列/字段
   */
  public List<ColumnRef> getColumns()
  {
    return columns;
  }

  /**
   * 设置字段
   *
   * @param columns 所有的列/字段
   */
  public void setColumns(final List<ColumnRef> columns)
  {
    this.columns = columns;
  }

  /**
   * 获取 tableName
   *
   * @return the value of tableName
   */
  public String getTableName()
  {
    return tableName;
  }

  /**
   * 设置 tableName
   *
   * @param tableName tableName
   */
  public void setTableName(final String tableName)
  {
    this.tableName = tableName;
  }

  /**
   * 获取 comment
   *
   * @return the value of comment
   */
  public String getComment()
  {
    return comment;
  }

  /**
   * 设置 comment
   *
   * @param comment comment
   */
  public void setComment(final String comment)
  {
    this.comment = comment;
  }

  /**
   * 获取 catalog
   *
   * @return the value of catalog
   */
  public String getCatalog()
  {
    return catalog;
  }

  /**
   * 设置 catalog
   *
   * @param catalog catalog
   */
  public void setCatalog(final String catalog)
  {
    this.catalog = catalog;
  }

  /**
   * 获取 schema
   *
   * @return the value of schema
   */
  public String getSchema()
  {
    return schema;
  }

  /**
   * 设置 schema
   *
   * @param schema schema
   */
  public void setSchema(final String schema)
  {
    this.schema = schema;
  }

  /**
   * 获取主键
   *
   * @return 主键
   */
  public PrimaryKeyRef getPrimaryKey()
  {
    return primaryKey;
  }

  /**
   * 设置主键
   *
   * @param primaryKey 主键
   */
  public void setPrimaryKey(final PrimaryKeyRef primaryKey)
  {

    ColumnRef columnRef = findColumn(primaryKey.getColumnName());
    columnRef.setPrimaryKey(true);
    primaryKey.setColumnRef(columnRef);
    this.primaryKey = primaryKey;
  }

  public ColumnRef findColumn(String columnName)
  {
    return this.columnRefMap.get(columnName);
  }

  /**
   * 获取外键集合
   *
   * @return 外键集合
   */
  public List<ForeignKeyRef> getForeignKeys()
  {
    return foreignKeys;
  }

  /**
   * 设置外键集合
   *
   * @param foreignKeys 外键集合
   */
  public void setForeignKeys(final List<ForeignKeyRef> foreignKeys)
  {
    this.foreignKeys = foreignKeys;
  }

  public List<IndexInfoRef> getIndexInfoRefs()
  {
    return indexInfoRefs;
  }

  public void setIndexInfoRefs(List<IndexInfoRef> indexInfoRefs)
  {
    this.indexInfoRefs = indexInfoRefs;
  }

  public void addIndexInfo(IndexInfoRef indexInfoRef)
  {
    if (primaryKey != null && indexInfoRef.getIndexName().equals(primaryKey.getPkName()))
    {
      return;
    }
    this.indexInfoRefs.add(indexInfoRef);
  }

  public void addIndexInfos(List<IndexInfoRef> indexInfoRefs)
  {
    for (IndexInfoRef indexInfo : indexInfoRefs)
    {
      this.addIndexInfo(indexInfo);
    }
  }

  /**
   * 获取表类型：表/视图
   *
   * @return 表类型：表/视图
   */
  public String getTableType()
  {
    return tableType;
  }

  /**
   * 设置表类型：表/视图
   *
   * @param tableType 表类型：表/视图
   */
  public void setTableType(final String tableType)
  {
    this.tableType = tableType;
  }

  /**
   * 添加字段集合
   *
   * @param columnRefs 字段集合
   */
  public void addColumns(final List<ColumnRef> columnRefs)
  {
    for (ColumnRef columnRef : columnRefs)
    {
      this.addColumn(columnRef);
    }
  }

  /**
   * 添加字段引用
   *
   * @param columnRef 字段
   */
  public void addColumn(final ColumnRef columnRef)
  {
    this.columnRefMap.put(columnRef.getName(), columnRef);
    this.columns.add(columnRef);
    analyseColumn(columnRef);
  }


  /**
   * 标记
   */
  private static final String FLAG = "@";
  /**
   * 注释左边界
   */
  private static final String LEFT_MARGIN = "{";
  /**
   * 注释右边界
   */
  private static final String RIGHT_MARGIN = "}";

  /**
   * 分割符
   */
  private static final char SPLIT_FK = '.';

  /**
   * 外键标记
   */
  public static final String FOREIGN_KEY = "FK";

  /**
   * 数据字段标记
   */
  public static final String DICT_CATALOG = "DICT";

  /**
   * 分析字段
   *
   * @param columnRef 字段
   */
  public void analyseColumn(final ColumnRef columnRef)
  {
    String columnComment = columnRef.getComment();
    if (columnComment == null || "".equalsIgnoreCase(columnComment.trim()))
    {
      return;
    }
    int flagIdx = columnComment.indexOf(FLAG);
    if (flagIdx >= 0)
    {
      String expression = columnComment.substring(flagIdx + 1);
      String[] exprs = expression.split(FLAG);
      for (String exp : exprs)
      {
        int leftMarginIdx = exp.indexOf(LEFT_MARGIN);
        int rightMarginIdx = exp.indexOf(RIGHT_MARGIN);
        if (leftMarginIdx <= 0 || rightMarginIdx <= 0)
        {
          return;
        }
        String type = exp.substring(0, leftMarginIdx);
        String content = exp.substring(leftMarginIdx + 1, rightMarginIdx);
        if (FOREIGN_KEY.equalsIgnoreCase(type))
        {
          String pkTableName;
          String pkColumnName;
          int idx = content.indexOf(SPLIT_FK);
          if (idx > 0)
          {
            pkTableName = content.substring(0, idx);
            pkColumnName = content.substring(idx + 1);
          } else
          {
            pkTableName = content;
            pkColumnName = "ID";
          }
          ForeignKeyRef foreignKey = new ForeignKeyRef(pkTableName, pkColumnName, tableName, columnRef.getName(), "");
          this.addForeignKey(foreignKey);
        }
      }
    }
  }
}
