package org.minimalj.backend.db;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Set;

import org.minimalj.model.annotation.AnnotationUtil;
import org.minimalj.model.properties.Properties;
import org.minimalj.model.properties.PropertyInterface;
import org.minimalj.util.IdUtils;

/**
 * The db product specifics
 * 
 */
public abstract class DbSyntax {

	protected void addCreateStatementBegin(StringBuilder s, String tableName) {
		s.append("CREATE TABLE "); s.append(tableName); s.append(" (\n");
	} 

	protected void addIdColumn(StringBuilder s, PropertyInterface idProperty) {
		Class<?> fieldClazz = idProperty.getClazz();
		int size = fieldClazz == String.class ? AnnotationUtil.getSize(idProperty) : 0;
		addIdColumn(s, fieldClazz, size);
	}
	
	protected void addIdColumn(StringBuilder s, Class<?> idClass, int size) {
		s.append(" id ");
		if (idClass == Integer.class) {
			s.append("INT");
		} else if (idClass == String.class) {
			s.append("VARCHAR(");
			s.append(size);
			s.append(")");
		} else if (idClass == Object.class) {
			s.append("CHAR(36)");
		} else {
			throw new IllegalArgumentException();
		}
		s.append(" NOT NULL");
//		if (idClass == Integer.class || idClass == Long.class) {
//			addAutoIncrement(s);
//		}
	}

//  to be supported again later
//	protected void addAutoIncrement(StringBuilder s) {
//		s.append(" AUTO_INCREMENT");
//	}
	
	/**
	 * Only public for tests. If this method doesnt throw an IllegalArgumentException
	 * then a property is valid
	 * 
	 * @param s
	 * @param property
	 */
	public void addColumnDefinition(StringBuilder s, PropertyInterface property) {
		Class<?> clazz = property.getClazz();
		
		if (clazz == Integer.class) {
			s.append("INTEGER");
		} else if (clazz == Long.class) {
			s.append("BIGINT");
		} else if (clazz == String.class) {
			s.append("VARCHAR");
			int size = AnnotationUtil.getSize(property);
			s.append(" ("); s.append(size); s.append(")");
		} else if (clazz == LocalDate.class) {
			s.append("DATE");
		} else if (clazz == LocalTime.class) {
			s.append("TIME");		
		} else if (clazz == LocalDateTime.class) {
			s.append("DATETIME"); // MariaDB. DerbyDB is different
		} else if (clazz == BigDecimal.class) {
			s.append("DECIMAL");
			int size = AnnotationUtil.getSize(property);
			int decimal = AnnotationUtil.getDecimal(property);
			if (decimal == 0) {
				s.append(" (" + size + ")");
			} else {
				s.append(" (" + size + ", " + decimal + ")");
			}
		} else if (clazz == Boolean.class) {
			s.append("BIT"); // MariaDB. DerbyDB is different
		} else if (Enum.class.isAssignableFrom(clazz)) {
			s.append("INTEGER");
		} else if (clazz == Set.class) {
			s.append("INTEGER");
		} else {
			if (IdUtils.hasId(clazz)) {
				PropertyInterface idProperty = Properties.getProperty(clazz, "id");
				addColumnDefinition(s, idProperty);
			} else {
				s.append("CHAR(36)");
			}
		}
	}
	
	protected void addPrimaryKey(StringBuilder s, String keys) {
		s.append(",\n PRIMARY KEY (");
		s.append(keys);
		s.append(")");
	}

	protected void addCreateStatementEnd(StringBuilder s) {
		s.append("\n)");
	}
	
	public String createConstraint(String tableName, String column, String referencedTableName, boolean referencedTableIsHistorized) {
		StringBuilder s = new StringBuilder();
		s.append("ALTER TABLE "); s.append(tableName);
		s.append(" ADD CONSTRAINT FK_");
		s.append(tableName); s.append("_"); s.append(column);
		s.append(" FOREIGN KEY (");
		s.append(column);
		s.append(") REFERENCES ");
		s.append(referencedTableName);
		s.append(" (ID)"); // not used at the moment: INITIALLY DEFERRED
		return s.toString();
	}
	
	public String createIndex(String tableName, String column, boolean withVersion) {
		StringBuilder s = new StringBuilder();
		s.append("CREATE INDEX IDX_");
		s.append(tableName);
		s.append('_');
		s.append(column);
		s.append(" ON ");
		s.append(tableName);
		s.append("(");
		s.append(column);
		if (withVersion) {
			s.append(", version");
		}
		s.append(")");
		return s.toString();
	}
	
	public String createUniqueIndex(String tableName, String column) {
		StringBuilder s = new StringBuilder();
		s.append("ALTER TABLE ");
		s.append(tableName);
		s.append(" ADD UNIQUE INDEX ");
		s.append(column);
		s.append(" (");
		s.append(column);
		s.append(")");
		return s.toString();
	}
	
	public static class MariaDbSyntax extends DbSyntax {
		
		@Override
		protected void addCreateStatementEnd(StringBuilder s) {
			s.append("\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED\n");
		}
	}
	
	public static class DerbyDbSyntax extends DbSyntax {

//		@Override
//		protected void addAutoIncrement(StringBuilder s) {
//			s.append(" GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1)");
//		}
		
		@Override
		public void addColumnDefinition(StringBuilder s, PropertyInterface property) {
			Class<?> clazz = property.getClazz();
			
			if (clazz == LocalDateTime.class) {
				s.append("TIMESTAMP");
			} else if (clazz == Boolean.class) {
				s.append("SMALLINT");
			} else {
				super.addColumnDefinition(s, property);
			}
		}
		
		@Override
		public void addPrimaryKey(StringBuilder s, String keys) {
			if (keys.indexOf(",") < 0) {
				super.addPrimaryKey(s, keys);
			} else {
				// no multi column primary keys possible
			}
		}
		
		@Override
		public String createConstraint(String tableName, String column, String referencedTableName, boolean referencedTableIsHistorized) {
			if (!referencedTableIsHistorized) {
				return super.createConstraint(tableName, column, referencedTableName, referencedTableIsHistorized);
			} else {
				return null;
			}
		}
		
		public String createUniqueIndex(String tableName, String column) {
			StringBuilder s = new StringBuilder();
			s.append("ALTER TABLE ");
			s.append(tableName);
			s.append(" ADD CONSTRAINT ");
			s.append(column);
			s.append("_UNIQUE UNIQUE (");
			s.append(column);
			s.append(")");
			return s.toString();
		}
	}
	
}

@@ -1628,49 +1628,8 @@
 id%0D%0A
-%09 * %0D%0A%09 * @param s%0D%0A%09 * @param property%0D%0A
 %09 */

remove dead java doc