package xugu

import (
	"database/sql"
	"reflect"
	"time"
)

type NullTime struct {
	Time  time.Time
	Valid bool // Valid is true if Time is not NULL
}

type xugusqlField struct {
	tableName string

	/*
	 * Store the name of the column
	 * name of the current field
	 * */
	name   string
	length int

	/*
	 * Store the data type information
	 * of the current field column
	 * */
	fieldType fieldType
}

const (
	TYPE_EMPTY        = 0
	TYPE_NULL         = 1
	TYPE_BOOL         = 2
	TYPE_I1           = 3
	TYPE_I2           = 4
	TYPE_I4           = 5
	TYPE_I8           = 6
	TYPE_NUM          = 7
	TYPE_R4           = 8
	TYPE_R8           = 9
	TYPE_DATE         = 10
	TYPE_TIME         = 11
	TYPE_TIME_TZ      = 12
	TYPE_DATETIME     = 13
	TYPE_DATETIME_TZ  = 14
	TYPE_INTERVAL_Y   = 15
	TYPE_INTERVAL_Y2M = 16
	TYPE_INTERVAL_M   = 17
	TYPE_INTERVAL_D   = 18
	TYPE_INTERVAL_D2H = 19
	TYPE_INTERVAL_H   = 20
	TYPE_INTERVAL_D2M = 21
	TYPE_INTERVAL_H2M = 22
	TYPE_INTERVAL_MI  = 23
	TYPE_INTERVAL_D2S = 24
	TYPE_INTERVAL_H2S = 25
	TYPE_INTERVAL_M2S = 26
	TYPE_INTERVAL_S   = 27
	TYPE_ROWVER       = 28
	TYPE_GUID         = 29
	TYPE_CHAR         = 30
	TYPE_NCHAR        = 31
	TYPE_CLOB         = 32
	TYPE_BINARY       = 33
	TYPE_BLOB         = 34
	TYPE_GEOM         = 35
	TYPE_POINT        = 36
	TYPE_BOX          = 37
	TYPE_POLYLINE     = 38
	TYPE_POLYGON      = 39
	TYPE_BLOB_I       = 40
	TYPE_BLOB_S       = 41
	TYPE_BLOB_M       = 42
	TYPE_BLOB_OM      = 43
	TYPE_STREAM       = 44
	TYPE_ROWID        = 45
	TYPE_SIBLING      = 46
	TYPE_MAX_SYS      = 47
	TYPE_BLADE_BEGIN  = 101
	TYPE_BLADE_END    = 1000
	TYPE_OBJECT       = 1001
	TYPE_REFROW       = 1002
	TYPE_RECORD       = 1003
	TYPE_VARRAY       = 1004
	TYPE_TABLE        = 1005
	TYPE_ITABLE       = 1006
	TYPE_CURSOR       = 1007
	TYPE_REFCUR       = 1008
	TYPE_ROWTYPE      = 1009
	TYPE_COLTYPE      = 1010
	TYPE_CUR_REC      = 1011
	TYPE_PARAM        = 1012
)

const (
	XG_C_NULL                   = 0
	XG_C_BOOL                   = 1
	XG_C_CHAR                   = 2
	XG_C_TINYINT                = 3
	XG_C_SHORT                  = 4
	XG_C_INTEGER                = 5
	XG_C_BIGINT                 = 6
	XG_C_FLOAT                  = 7
	XG_C_DOUBLE                 = 8
	XG_C_NUMERIC                = 9
	XG_C_DATE                   = 10
	XG_C_TIME                   = 11
	XG_C_TIME_TZ                = 12
	XG_C_DATETIME               = 13
	XG_C_DATETIME_TZ            = 14
	XG_C_BINARY                 = 15
	XG_C_INTERVAL               = 21
	XG_C_INTERVAL_YEAR_TO_MONTH = 28
	XG_C_INTERVAL_DAY_TO_SECOND = 31
	XG_C_CLOB                   = 41
	XG_C_BLOB                   = 42
)

type fieldType byte

const (
	fieldTypeBool fieldType = iota + 0x01
	fieldTypeChar
	fieldTypeTinyint
	fieldTypeShort
	fieldTypeInteger
	fieldTypeBigint
	fieldTypeFloat
	fieldTypeDouble
	fieldTypeNumeric
	fieldTypeDate
	fieldTypeTime
	fieldTypeTimeTZ
	fieldTypeDatetime   fieldType = 23
	fieldTypeDatetimeTZ fieldType = 14
	fieldTypeBinary     fieldType = 15

	fieldTypeInterval    fieldType = 21
	fieldTypeIntervalY2M fieldType = 28
	fieldTypeIntervalD2S fieldType = 31
	fieldTypeLob         fieldType = 40
	fieldTypeClob        fieldType = 41
	fieldTypeBlob        fieldType = 42
)

func getSQLCType(typeID uint32) int32 {
	switch typeID {
	case TYPE_BOOL:
		return XG_C_BOOL
	case TYPE_I1:
		return XG_C_TINYINT
	case TYPE_I2:
		return XG_C_SHORT
	case TYPE_I4:
		return XG_C_INTEGER
	case TYPE_I8:
		return XG_C_BIGINT
	case TYPE_R4:
		return XG_C_FLOAT
	case TYPE_R8:
		return XG_C_DOUBLE
	case TYPE_NUM:
		return XG_C_NUMERIC
	case TYPE_DATETIME:
		return XG_C_DATETIME
	case TYPE_DATETIME_TZ:
		return XG_C_DATETIME_TZ
	case TYPE_INTERVAL_Y2M:
		return XG_C_INTERVAL_YEAR_TO_MONTH
	case TYPE_INTERVAL_D2S:
		return XG_C_INTERVAL_DAY_TO_SECOND
	case TYPE_GUID:
		return TYPE_GUID + 40
	case TYPE_TIME_TZ:
		return XG_C_TIME_TZ
	case TYPE_DATE:
		return XG_C_DATE
	case TYPE_TIME:
		return XG_C_TIME
	case TYPE_BINARY:
		return XG_C_BINARY
	case TYPE_CLOB:
		return XG_C_CLOB
	case TYPE_BLOB:
		return XG_C_BLOB
	case TYPE_INTERVAL_Y, TYPE_INTERVAL_M, TYPE_INTERVAL_D, TYPE_INTERVAL_H,
		TYPE_INTERVAL_MI, TYPE_INTERVAL_S, TYPE_INTERVAL_D2H, TYPE_INTERVAL_D2M,
		TYPE_INTERVAL_H2M, TYPE_INTERVAL_H2S, TYPE_INTERVAL_M2S:
		return XG_C_INTERVAL
	default:
		return XG_C_CHAR
	}
}

/* {{ */
func (self *xugusqlField) typeDatabaseName() string {
	switch self.fieldType {
	case fieldTypeBool:
		return "BOOLEAN"
	case fieldTypeChar:
		return "CHAR"
	case fieldTypeTinyint:
		return "TINYINT"
	case fieldTypeShort:
		return "SHORT"
	case fieldTypeInteger:
		return "INTEGER"
	case fieldTypeBigint:
		return "BIGINT"
	case fieldTypeFloat:
		return "FLOAT"
	case fieldTypeDouble:
		return "DOUBLE"
	case fieldTypeNumeric:
		return "NUMERIC"
	case fieldTypeDate:
		return "DATE"
	case fieldTypeTime:
		return "TIME"
	case fieldTypeTimeTZ:
		return "TIMEZONE"
	case fieldTypeDatetime:
		return "DATETIME"
	case fieldTypeDatetimeTZ:
		return "DATETIME TIMEZONE"
	case fieldTypeBinary:
		return "BINARY"
	case fieldTypeInterval:
		return "INTERVAL"
	case fieldTypeIntervalY2M:
		return "INTERVAL YEAR TO MONTH"
	case fieldTypeIntervalD2S:
		return "INTERVAL DAY TO SECOND"
	case fieldTypeClob:
		return "CLOB"
	case fieldTypeBlob:
		return "BLOB"
	default:
		return ""
	}
}

/* {{ */
func (self *xugusqlField) scanType() reflect.Type {
	switch self.fieldType {
	case fieldTypeBool:
		return scanTypeBool
	case fieldTypeTinyint:
		return scanTypeInt8
	case fieldTypeShort:
		return scanTypeInt16
	case fieldTypeInteger:
		return scanTypeInt32
	case fieldTypeBigint:
		return scanTypeInt64
	case fieldTypeFloat:
		return scanTypeFloat32
	case fieldTypeDouble:
		return scanTypeFloat64
	case fieldTypeDate,
		fieldTypeTime,
		fieldTypeDatetime:
		return scanTypeNullTime
	case fieldTypeTimeTZ,
		fieldTypeDatetimeTZ,
		fieldTypeChar,
		fieldTypeBinary,
		fieldTypeInterval,
		fieldTypeNumeric,
		fieldTypeIntervalY2M,
		fieldTypeIntervalD2S,
		fieldTypeLob,
		fieldTypeClob,
		fieldTypeBlob:
		return scanTypeRawBytes
	default:
		return scanTypeUnknown

	}
}

var (
	scanTypeFloat32   = reflect.TypeOf(float32(0))
	scanTypeFloat64   = reflect.TypeOf(float64(0))
	scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
	scanTypeNullInt   = reflect.TypeOf(sql.NullInt64{})
	scanTypeNullTime  = reflect.TypeOf(time.Time{})
	scanTypeInt8      = reflect.TypeOf(int8(0))
	scanTypeInt16     = reflect.TypeOf(int16(0))
	scanTypeInt32     = reflect.TypeOf(int32(0))
	scanTypeInt64     = reflect.TypeOf(int64(0))
	scanTypeUnknown   = reflect.TypeOf(new(interface{}))
	scanTypeRawBytes  = reflect.TypeOf(sql.RawBytes{})
	scanTypeUint8     = reflect.TypeOf(uint8(0))
	scanTypeUint16    = reflect.TypeOf(uint16(0))
	scanTypeUint32    = reflect.TypeOf(uint32(0))
	scanTypeUint64    = reflect.TypeOf(uint64(0))
	scanTypeBool      = reflect.TypeOf(bool(false))
)