package exp

import "strings"

type (
	identifier struct {
		schema string
		table  string
		col    interface{}
	}
)

func ParseIdentifier(ident string) IdentifierExpression {
	parts := strings.Split(ident, ".")
	switch len(parts) {
	case 2:
		return NewIdentifierExpression("", parts[0], parts[1])
	case 3:
		return NewIdentifierExpression(parts[0], parts[1], parts[2])
	}
	return NewIdentifierExpression("", "", ident)
}

func NewIdentifierExpression(schema, table string, col interface{}) IdentifierExpression {
	return identifier{}.Schema(schema).Table(table).Col(col)
}

func (i identifier) clone() identifier {
	return identifier{schema: i.schema, table: i.table, col: i.col}
}

func (i identifier) Clone() Expression {
	return i.clone()
}

// Sets the table on the current identifier
//  I("col").Table("table") -> "table"."col" //postgres
//  I("col").Table("table") -> `table`.`col` //mysql
//  I("col").Table("table") -> `table`.`col` //sqlite3
func (i identifier) Table(table string) IdentifierExpression {
	i.table = table
	return i
}

func (i identifier) GetTable() string {
	return i.table
}

// Sets the table on the current identifier
//  I("table").Schema("schema") -> "schema"."table" //postgres
//  I("col").Schema("table") -> `schema`.`table` //mysql
//  I("col").Schema("table") -> `schema`.`table` //sqlite3
func (i identifier) Schema(schema string) IdentifierExpression {
	i.schema = schema
	return i
}

func (i identifier) GetSchema() string {
	return i.schema
}

// Sets the table on the current identifier
//  I("table").Col("col") -> "table"."col" //postgres
//  I("table").Schema("col") -> `table`.`col` //mysql
//  I("table").Schema("col") -> `table`.`col` //sqlite3
func (i identifier) Col(col interface{}) IdentifierExpression {
	if col == "*" {
		i.col = Star()
	} else {
		i.col = col
	}
	return i
}

func (i identifier) Expression() Expression { return i }

// Qualifies the epression with a * literal (e.g. "table".*)
func (i identifier) All() IdentifierExpression { return i.Col("*") }

func (i identifier) IsEmpty() bool {
	isEmpty := i.schema == "" && i.table == ""
	if isEmpty {
		switch t := i.col.(type) {
		case nil:
			return true
		case string:
			return t == ""
		default:
			return false
		}
	}
	return isEmpty
}

// Gets the column identifier
func (i identifier) GetCol() interface{} { return i.col }

// Used within updates to set a column value
func (i identifier) Set(val interface{}) UpdateExpression { return set(i, val) }

// Alias an identifier (e.g "my_col" AS "other_col")
func (i identifier) As(val interface{}) AliasedExpression { return aliased(i, val) }

// Returns a BooleanExpression for equality (e.g "my_col" = 1)
func (i identifier) Eq(val interface{}) BooleanExpression { return eq(i, val) }

// Returns a BooleanExpression for in equality (e.g "my_col" != 1)
func (i identifier) Neq(val interface{}) BooleanExpression { return neq(i, val) }

// Returns a BooleanExpression for checking that a identifier is greater than another value (e.g "my_col" > 1)
func (i identifier) Gt(val interface{}) BooleanExpression { return gt(i, val) }

// Returns a BooleanExpression for checking that a identifier is greater than or equal to another value
// (e.g "my_col" >= 1)
func (i identifier) Gte(val interface{}) BooleanExpression { return gte(i, val) }

// Returns a BooleanExpression for checking that a identifier is less than another value (e.g "my_col" < 1)
func (i identifier) Lt(val interface{}) BooleanExpression { return lt(i, val) }

// Returns a BooleanExpression for checking that a identifier is less than or equal to another value
// (e.g "my_col" <= 1)
func (i identifier) Lte(val interface{}) BooleanExpression { return lte(i, val) }

// Returns a BooleanExpression for checking that a identifier is in a list of values or  (e.g "my_col" > 1)
func (i identifier) In(vals ...interface{}) BooleanExpression    { return in(i, vals...) }
func (i identifier) NotIn(vals ...interface{}) BooleanExpression { return notIn(i, vals...) }
func (i identifier) Like(val interface{}) BooleanExpression      { return like(i, val) }
func (i identifier) NotLike(val interface{}) BooleanExpression   { return notLike(i, val) }
func (i identifier) ILike(val interface{}) BooleanExpression     { return iLike(i, val) }
func (i identifier) NotILike(val interface{}) BooleanExpression  { return notILike(i, val) }
func (i identifier) Is(val interface{}) BooleanExpression        { return is(i, val) }
func (i identifier) IsNot(val interface{}) BooleanExpression     { return isNot(i, val) }
func (i identifier) IsNull() BooleanExpression                   { return is(i, nil) }
func (i identifier) IsNotNull() BooleanExpression                { return isNot(i, nil) }
func (i identifier) IsTrue() BooleanExpression                   { return is(i, true) }
func (i identifier) IsNotTrue() BooleanExpression                { return isNot(i, true) }
func (i identifier) IsFalse() BooleanExpression                  { return is(i, false) }
func (i identifier) IsNotFalse() BooleanExpression               { return isNot(i, false) }
func (i identifier) Asc() OrderedExpression                      { return asc(i) }
func (i identifier) Desc() OrderedExpression                     { return desc(i) }
func (i identifier) Distinct() SQLFunctionExpression             { return NewSQLFunctionExpression("DISTINCT", i) }
func (i identifier) Cast(t string) CastExpression                { return NewCastExpression(i, t) }

// Returns a RangeExpression for checking that a identifier is between two values (e.g "my_col" BETWEEN 1 AND 10)
func (i identifier) Between(val RangeVal) RangeExpression { return between(i, val) }

// Returns a RangeExpression for checking that a identifier is between two values (e.g "my_col" BETWEEN 1 AND 10)
func (i identifier) NotBetween(val RangeVal) RangeExpression { return notBetween(i, val) }
