/*
 * blancoDb
 * Copyright (C) 2004-2005 Yasuo Nakanishi
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.db.expander.table.gateway.sql;

import blanco.db.conf.BlancoDbSetting;
import blanco.db.definition.TableField;
import blanco.db.definition.TableGateway;
import blanco.db.util.BlancoDbObjectStorage;
import blanco.ig.expander.NameAdjuster;
import blanco.ig.expander.Type;

/**
 * @author Yasuo Nakanishi
 */
public abstract class SqlGenerator {
    private Type _rowType = null;

    private TableGateway _gateway = null;

    private NameAdjuster _adjuster = null;

    private BlancoDbSetting _setting = null;

    private String _lfln = "";

    public SqlGenerator(Type rowType, TableGateway gateway) {
        _rowType = rowType;
        _gateway = gateway;
        _lfln = getSystemLfln();
        _adjuster = new NameAdjuster();
        _setting = BlancoDbObjectStorage.getInstance().getSetting();
    }

    private String getSystemLfln() {
        String lfln = System.getProperty("line.separator");
        return lfln.replaceAll("\\r", "\\\\r").replaceAll("\\n", "\\\\n");
    }

    private String newLine() {
        String result = "";
        return result;
    }

    public String getSelect() {
        StringBuffer sb = new StringBuffer();
        sb.append(adjust("select "));
        sb.append(getFieldString());
        sb.append(newLine());
        sb.append(adjust(" from "));
        sb.append(getTableName(_gateway.getDbName()));
        sb.append(newLine());
        sb.append(adjust(" where "));

        TableField field = null;
        boolean isNotFirstPrimaryKey = false;
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            field = _gateway.getField(i);

            if (!isNotFirstPrimaryKey && field.isPrimaryKey()) {
                isNotFirstPrimaryKey = true;
            } else if (isNotFirstPrimaryKey && field.isPrimaryKey()) {
                sb.append(adjust(" and "));
            }

            if (field.isPrimaryKey()) {
                sb.append(getFieldName(field.getJdbcName()));
                sb.append(" = ");
                sb.append(getPrimaryKeyValueName(field));
            }
        }
        return new String(sb);
    }

    private String getPrimaryKeyValueName(TableField field) {
        return "#" + _adjuster.toValueName(field.getName());
    }

    private String getRowValueName(TableField field) {
        StringBuffer sb = new StringBuffer();
        sb.append("#");
        sb.append(_adjuster.toValueName(_rowType.getName()));
        sb.append(".");
        sb.append(_adjuster.toValueName(field.getName()));
        return sb.toString();
    }

    public String getSelectAll() {
        StringBuffer sb = new StringBuffer();
        sb.append(adjust("select "));
        sb.append(getFieldString());
        sb.append(newLine());
        sb.append(adjust(" from "));
        sb.append(getTableName(_gateway.getDbName()));
        sb.append(newLine());
        sb.append(adjust(" order by "));

        TableField field = null;
        boolean isNotFirstPrimaryKey = false;
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            field = _gateway.getField(i);

            if (!isNotFirstPrimaryKey && field.isPrimaryKey()) {
                isNotFirstPrimaryKey = true;
            } else if (isNotFirstPrimaryKey && field.isPrimaryKey()) {
                sb.append(", ");
            }

            if (field.isPrimaryKey()) {
                sb.append(getFieldName(field.getJdbcName()));
            }
        }
        return new String(sb);
    }

    public String getInsert() {
        StringBuffer sb = new StringBuffer();
        sb.append(adjust("insert into "));
        sb.append(getTableName(_gateway.getDbName()));
        sb.append(" (");
        sb.append(getFieldString());
        sb.append(adjust(")"));
        sb.append(newLine());
        sb.append(adjust(" values ("));

        TableField field = null;
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            field = _gateway.getField(i);
            if (i != 0) {
                sb.append(", ");
            }
            sb.append(getRowValueName(field));
        }
        sb.append(")");
        return new String(sb);
    }

    private String getFieldString() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            if (i != 0) {
                sb.append(", ");
            }
            sb.append(getFieldName(_gateway.getField(i).getJdbcName()));
        }
        return sb.toString();
    }

    public String getUpdate() {
        StringBuffer sb = new StringBuffer("");
        sb.append(adjust("update "));
        sb.append(getTableName(_gateway.getDbName()));
        sb.append(newLine());
        sb.append(adjust(" set "));

        TableField field = null;
        boolean isFirstField = false;
        String fieldName = "";
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            field = _gateway.getField(i);
            fieldName = field.getJdbcName();

            if (!isFirstField && !field.isPrimaryKey()) {
                isFirstField = true;
            } else if (!field.isPrimaryKey()) {
                sb.append(", ");
            }

            if (!field.isPrimaryKey()) {
                sb.append(getFieldName(fieldName));
                sb.append(" = ");
                sb.append(getRowValueName(field));
            }
        }
        isFirstField = false;
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            field = _gateway.getField(i);

            if (!isFirstField && field.isPrimaryKey()) {
                isFirstField = true;
                sb.append(newLine());
                sb.append(adjust(" where "));
            } else if (field.isPrimaryKey()) {
                sb.append(adjust(" and "));
            }

            if (field.isPrimaryKey()) {
                sb.append(getFieldName(field.getJdbcName()));
                sb.append(" = ");
                sb.append(getRowValueName(field));
            }
        }
        return new String(sb);
    }

    private String adjust(String sqlKey) {
        String result = sqlKey;
        if (!isUsingLowerCase()) {
            result = sqlKey.toUpperCase();
        }
        return result;
    }

    public String getDelete() {
        StringBuffer sb = new StringBuffer();
        sb.append(adjust("delete from "));
        sb.append(getTableName(_gateway.getDbName()));
        sb.append(newLine());
        sb.append(adjust(" where "));

        TableField field = null;
        boolean isNotFirstKey = false;
        for (int i = 0; i < _gateway.getFiledCount(); i++) {
            field = _gateway.getField(i);
            if (!isNotFirstKey && field.isPrimaryKey()) {
                isNotFirstKey = true;
            } else if (field.isPrimaryKey()) {
                sb.append(adjust(" and "));
            }
            if (field.isPrimaryKey()) {
                sb.append(getFieldName(field.getJdbcName()));
                sb.append(" = #");
                sb.append(_adjuster.toValueName(field.getName()));
            }
        }
        return new String(sb);
    }

    protected boolean isUsingLowerCase() {
        // デフォルトでSQLは大文字です。
        return false;
    }

    protected String getFieldName(String fieldName) {
        StringBuffer sb = new StringBuffer();
        if (fieldName.indexOf(" ") == -1) {
            sb.append(fieldName);
        } else {
            sb.append("\\\"");
            sb.append(fieldName);
            sb.append("\\\"");
        }
        return sb.toString();
    }

    protected String getTableName(String tableName) {
        StringBuffer sb = new StringBuffer();
        sb.append("\\\"");
        sb.append(tableName);
        sb.append("\\\"");
        return sb.toString();
    }
}