/**
   * get the comma separated list of fields
   *
   * @param fields the fields for which to build the list
   * @return comma separated list of fields
   */
  public String getFieldList(List<Field> fields) {
    return CollectionUtil.join(
        fields,
        ",",
        new StringMutator() {

          @Override
          public String transform(Object s) {
            return new StringBuilder("$").append(getMemberName((Field) s)).toString();
          }
        });
  }
  /**
   * get all code
   *
   * @return all code
   */
  public String getCode() {
    StringBuilder s = new StringBuilder("<?php\n");
    s.append(getSnippetFromFile("CodeGenerator.class.php"));
    s.append("class ").append(getClassName());
    s.append(" extends Db2PhpEntityBase");
    if (getSettings().isUseInterfaces()) {
      // s.append(" implements Db2PhpEntity");
      s.append(" implements Db2PhpEntityModificationTracking");
    }
    if (!settings.getAdditionalInterfaces().isEmpty()) {
      if (!getSettings().isUseInterfaces()) {
        s.append(" implements ");
      } else {
        s.append(", ");
      }
      s.append(CollectionUtil.join(getSettings().getAdditionalInterfaces(), ", "));
    } else {
      s.append(" ");
    }
    s.append("{\n");
    s.append(getPreparedStatements());
    s.append(getConsts());
    s.append(getMembers());
    //		if (isTrackFieldModifications()) {
    //			s.append(getSnippetFromFile("CodeGenerator.modificationTracking.php"));
    //		}
    s.append(getAccessors());
    s.append(getSnippetFromFile("CodeGenerator.php"));
    s.append(getUtilMethodToArray());
    s.append(getUtilMethodgetPrimaryKeysToArray());
    s.append(getDatabaseLayer().getCode(this));

    if (getSettings().isEzComponents()) {
      s.append(getSnippetFromFile("CodeGenerator.ezc.php"));
    }
    s.append(getSnippetFromFile("CodeGenerator.dom.php"));
    // s.append(getSnippetFromFile("CodeGenerator.toString.php"));
    s.append("}\n");
    s.append("?>");
    return s.toString();
  }
  /**
   * helper method to generate array for passed fields
   *
   * @param fields the fields which to add to the array
   * @param methodName the name for the method
   * @return code to generate array from passed fields
   */
  private String getUtilMethodArray(Set<Field> fields, String methodName) {
    StringBuilder s = new StringBuilder("\tpublic function ").append(methodName).append("() {\n");
    s.append("\t\treturn array(\n");
    s.append(
        CollectionUtil.join(
            fields,
            ",\n",
            new StringMutator() {

              @Override
              public String transform(Object s) {
                Field f = (Field) s;
                return new StringBuilder("\t\t\tself::")
                    .append(getConstName(f))
                    .append("=>")
                    .append(getGetterCall(f))
                    .toString();
              }
            }));
    // s.append("\t\treturn $this->").append(getMemberName(field)).append(";\n");
    s.append(");\n");
    s.append("\t}\n");
    return s.toString();
  }
  /**
   * get the prepared statements
   *
   * @return the INSERT/UPDATE/SELECT/DELETE prepared statements
   */
  public String getPreparedStatements() {
    Set<Field> fields = getTable().getFields();
    StringBuilder s = new StringBuilder();
    s.append("\tprivate static $CLASS_NAME=").append(getPhpString(getClassName())).append(";\n");
    s.append("\tconst SQL_IDENTIFIER_QUOTE='").append(getIdentifierQuoteString()).append("';\n");
    s.append("\tconst SQL_TABLE_NAME=").append(getPhpString(getTable().getName())).append(";\n");

    // insert query
    s.append("\tconst SQL_INSERT='INSERT INTO ").append(quoteIdentifier(getTable().getName()));
    s.append(" (")
        .append(
            CollectionUtil.join(
                fields, ",", getIdentifierQuoteString(), getIdentifierQuoteString()))
        .append(") VALUES (")
        .append(StringUtil.repeat("?,", fields.size() - 1))
        .append("?)")
        .append("';\n");

    // insert query with autoincrement columns omitted
    // if (!getTable().getFieldsAutoIncrement().isEmpty()) {
    Set<Field> fieldsNotAutoincrement = getTable().getFieldsNotAutoIncrement();
    s.append("\tconst SQL_INSERT_AUTOINCREMENT='INSERT INTO ")
        .append(quoteIdentifier(getTable().getName()));
    s.append(" (")
        .append(
            CollectionUtil.join(
                fieldsNotAutoincrement,
                ",",
                getIdentifierQuoteString(),
                getIdentifierQuoteString()))
        .append(") VALUES (")
        .append(StringUtil.repeat("?,", fieldsNotAutoincrement.size() - 1))
        .append("?)")
        .append("';\n");
    // }

    // update query
    s.append("\tconst SQL_UPDATE='UPDATE ").append(quoteIdentifier(getTable().getName()));
    s.append(" SET ");
    StringMutator fieldAssign =
        new StringMutator() {

          @Override
          public String transform(Object s) {
            return new StringBuilder()
                .append(getIdentifierQuoteString())
                .append(((Field) s).getName())
                .append(getIdentifierQuoteString())
                .append("=?")
                .toString();
          }
        };
    s.append(CollectionUtil.join(fields, ",", fieldAssign));
    Set<Field> keys = getTable().getFieldsIdentifiers();
    StringBuilder sqlWhere = new StringBuilder();
    if (!keys.isEmpty()) {
      sqlWhere.append(" WHERE ");
      sqlWhere.append(CollectionUtil.join(keys, " AND ", fieldAssign));
    }
    s.append(sqlWhere);
    s.append("';\n");

    // select by id
    s.append("\tconst SQL_SELECT_PK='SELECT * FROM ").append(quoteIdentifier(getTable().getName()));
    s.append(sqlWhere);
    s.append("';\n");

    // delete by id
    s.append("\tconst SQL_DELETE_PK='DELETE FROM ").append(quoteIdentifier(getTable().getName()));
    s.append(sqlWhere);
    s.append("';\n");
    return s.toString();
  }
  /**
   * get constant definitions for fields ids
   *
   * @return constant definitions for fields ids
   */
  public String getConsts() {
    StringBuilder s = new StringBuilder();
    // field ids for misc use
    int i = 0;
    for (Field f : getTable().getFields()) {
      // s.append("\tconst FIELD_").append(getMethodName(f).toUpperCase()).append("=").append((int)
      // Math.pow(2, i++)).append("\n");
      // s.append("\tconst ").append(getConstName(f)).append("=").append(i++).append(";\n");
      s.append("\tconst ").append(getConstName(f)).append("=").append(getHash(f)).append(";\n");
    }

    StringMutator mutatorFieldList =
        new StringMutator() {

          @Override
          public String transform(Object s) {
            return new StringBuilder("self::").append(getConstName((Field) s)).toString();
          }
        };
    // list of primary keys
    s.append("\tprivate static $PRIMARY_KEYS=array(");
    s.append(CollectionUtil.join(getTable().getFieldsIdentifiers(), ",", mutatorFieldList));
    s.append(");\n");

    // list of autoincrement fields
    s.append("\tprivate static $AUTOINCREMENT_FIELDS=array(");
    s.append(CollectionUtil.join(getTable().getFieldsAutoIncrement(), ",", mutatorFieldList));
    s.append(");\n");

    /*
    // list of imported keys
    s.append("\tprivate static $EXPORTED_KEYS=array(");
    s.append(CollectionUtil.join(getTable().getImportedKeys(), ",", new StringMutator() {

    	@Override
    	public String transform(Object input) {
    		ForeignKey fk=(ForeignKey) input;
    		StringBuilder s=new StringBuilder();
    		s.append("\t\tself::").append(getConstName(fk.getPkField()));
    		return s.toString();
    		//return new StringBuilder("self::").append(getConstName((Field) i)).toString();
    	}
    }));
    s.append(");\n");

    // list of imported keys
    s.append("\tprivate static $IMPORTED_KEYS=array(");
    s.append(CollectionUtil.join(getTable().getExportedKeys(), ",", mutatorFieldList));
    s.append(");\n");
    */

    // field id to field name mapping
    s.append("\tprivate static $FIELD_NAMES=array(\n");
    s.append(
        CollectionUtil.join(
            getTable().getFields(),
            ",\n",
            new StringMutator() {

              @Override
              public String transform(Object s) {
                Field f = (Field) s;
                return new StringBuilder("\t\tself::")
                    .append(getConstName(f))
                    .append("=>")
                    .append(getPhpString(f.getName()))
                    .toString();
              }
            }));
    s.append(");\n");
    /*
    // field id to field type mapping
    s.append("\tprivate static $FIELD_TYPES=array(\n");
    s.append(CollectionUtil.join(getTable().getFields(), ",\n", new StringMutator() {

    	@Override
    	public String transform(Object s) {
    		Field f=(Field) s;
    		return new StringBuilder("\t\tself::").append(getConstName(f)).append("=>").append(getPhpString(f.getTypeName())).toString();
    	}
    }));
    s.append(");\n");
    */
    // field id to field property mapping
    s.append("\tprivate static $PROPERTY_NAMES=array(\n");
    s.append(
        CollectionUtil.join(
            getTable().getFields(),
            ",\n",
            new StringMutator() {

              @Override
              public String transform(Object s) {
                Field f = (Field) s;
                return new StringBuilder("\t\tself::")
                    .append(getConstName(f))
                    .append("=>")
                    .append(getPhpString(getMemberName(f)))
                    .toString();
              }
            }));
    s.append(");\n");

    // field id to property type mapping
    s.append("\tprivate static $PROPERTY_TYPES=array(\n");
    s.append(
        CollectionUtil.join(
            getTable().getFields(),
            ",\n",
            new StringMutator() {

              @Override
              public String transform(Object s) {
                Field f = (Field) s;
                return new StringBuilder("\t\tself::")
                    .append(getConstName(f))
                    .append("=>")
                    .append("Db2PhpEntity::PHP_TYPE_")
                    .append(f.getTypePHP().toUpperCase())
                    .toString();
              }
            }));
    s.append(");\n");
    // field id to property type mapping
    s.append("\tprivate static $FIELD_TYPES=array(\n");
    s.append(
        CollectionUtil.join(
            getTable().getFields(),
            ",\n",
            new StringMutator() {

              @Override
              public String transform(Object s) {
                Field f = (Field) s;
                StringBuilder code =
                    new StringBuilder("\t\tself::").append(getConstName(f)).append("=>array(");
                code.append("Db2PhpEntity::JDBC_TYPE_")
                    .append(f.getTypeSqlString() == null ? f.getType() : f.getTypeSqlString());
                code.append(",").append(f.getSize());
                code.append(",").append(f.getDecimalDigits());
                code.append(",").append(f.isNullable() ? "true" : "false");
                code.append(")");
                return code.toString();
              }
            }));
    s.append(");\n");

    // default values
    s.append("\tprivate static $DEFAULT_VALUES=array(\n");
    s.append(
        CollectionUtil.join(
            getTable().getFields(),
            ",\n",
            new StringMutator() {

              @Override
              public String transform(Object input) {
                Field f = (Field) input;
                StringBuilder s = new StringBuilder("\t\t");
                s.append("self::").append(getConstName(f)).append("=>");
                if (f.isAutoIncrement() || (f.isNullable() && null == f.getDefaultValue())) {
                  s.append("null");
                } else if (null == f.getDefaultValue()) {
                  if (f.isNumberType()) {
                    s.append("0");
                  } else {
                    s.append("''");
                  }
                } else {
                  if (f.isNumberType()) {
                    if (0 == f.getDefaultValue().length()) {
                      s.append("0");
                    } else {
                      if (f.getDefaultValue().matches(".*[^0-9\\.].*")) {
                        // s.append(getPhpString(f.getDefaultValue()));
                        s.append("null");
                      } else {
                        s.append(f.getDefaultValue());
                      }
                    }
                  } else {
                    s.append(getPhpString(f.getDefaultValue()));
                  }
                }
                return s.toString();
              }
            }));
    s.append(");\n");
    return s.toString();
  }