package core

import (
	"dbweb/lib/bill"
	"dbweb/lib/model"
	"reflect"

	"gopkg.in/yaml.v2"
)

const (
	//ModelElementName 是工作元素表的名称
	ModelElementName = "ELEMENT"
)
const (
	//ElementOwnerNormal 正常的工作元素
	ElementOwnerNormal int64 = 0
	//ElementOwnerAutoCreate 自动创建的工作元素
	ElementOwnerAutoCreate int64 = 1
	//True int64的true
	True int64 = 1
	//False int64的false
	False int64 = 0
)

var (
	//elementTypes 保存各种模块的工作元素实际类型
	elementTypes = map[string]interface{}{}
)

//ModelElementNoParam 工作元素model，没有params参数字段，方便各种类型参数的element嵌入使用
type ModelElementNoParam struct {
	Name       string `dbx:"STR(50) PRIMARY KEY"`
	Label      string `dbx:"STR(50)"`
	Category   string `dbx:"STR(300)"`
	Controller string `dbx:"STR(50) NOT NULL INDEX"`
	Pub        int64  `dbx:"INT NOT NULL"`
	Owner      int64  //这个字段0代表正常，1代表自动创建，具体怎样需要核实
	UserName   string `dbx:"STR(50)"`
	Dept       string `dbx:"STR(50) NOT NULL"`
	NewWindow  int64  `dbx:"INT"`
	HelpText   string `dbx:"STR"`
}

//modelElement 最通用的字符串参数的工作元素
type modelElement struct {
	ModelElementNoParam `yaml:",inline"`
	Params              string `dbx:"STR"`
}

//RestoreParam 恢复的工作元素
type RestoreParam struct {
	DumpName string
}

type ModelRestoreElement struct {
	ModelElementNoParam `yaml:",inline"`
	Params              RestoreParam `dbx:"STR"`
}
type modelBillElement struct {
	ModelElementNoParam `yaml:",inline"`
	Params              BillParam `dbx:"STR"`
}

//RegisterElementType 注册工作元素中，某个Controller对应的实际Element类型
func RegisterElementType(controllerName string, meta interface{}) {
	elementTypes[controllerName] = meta
}
func (e modelElement) OnAfterSchemaUpdate(md *model.Model, oldversion int64) error {

	//关键的几个菜单项，不能被改动
	eles := []interface{}{
		modelElement{
			ModelElementNoParam: ModelElementNoParam{
				Name:       "login",
				Label:      "登录",
				Category:   "(程序使用)/主界面",
				Controller: "login",
				Pub:        True,
				Owner:      ElementOwnerNormal,
				UserName:   "sys",
				Dept:       "r",
			},
		},
		modelElement{
			ModelElementNoParam: ModelElementNoParam{
				Name:       "logout",
				Label:      "退出系统",
				Category:   "(程序使用)/主界面",
				Controller: "login",
				Pub:        True,
				Owner:      ElementOwnerNormal,
				UserName:   "sys",
				Dept:       "r",
			},
		},
		modelElement{
			ModelElementNoParam: ModelElementNoParam{
				Name:       "index",
				Label:      "主界面",
				Category:   "我的账号/20.数据",
				Controller: "index",
				Pub:        False,
				Owner:      ElementOwnerNormal,
				UserName:   "sys",
				Dept:       "r",
			},
		},
		modelElement{
			ModelElementNoParam: ModelElementNoParam{
				Name:       "switchdept",
				Label:      "切换处理地",
				Category:   "(程序使用)/主界面",
				Controller: "switchdept",
				Pub:        False,
				Owner:      ElementOwnerNormal,
				UserName:   "sys",
				Dept:       "r",
			},
		},
	}
	for _, row := range eles {
		switch tv := row.(type) {
		case modelElement:
			LOG.Println("save", tv.Name)
		}
		if err := md.Set(row); err != nil {
			return err
		}
	}
	return nil
}

//Scan 制度包导出时转换用
func (e modelElement) MarshalInstitutioner(rec *bill.Record) ([]byte, error) {
	var out interface{} = &e
	if tt, ok := elementTypes[e.Controller]; ok {
		out = reflect.New(reflect.TypeOf(tt)).Interface()
		if err := rec.Scan(out); err != nil {
			return nil, err
		}
	}
	//如果是bill，则用modelelementbill
	if c := FindController(e.Controller); c == nil {
		LOG.Panic(e.Controller, "not found")
	} else if c.Bill {
		out = &modelBillElement{}
		if err := rec.Scan(out); err != nil {
			return nil, err
		}
	}
	return yaml.Marshal(out)
}
func (e *modelElement) UnmarshalInstitutioner(bys []byte) (out interface{}, err error) {
	if err = yaml.Unmarshal(bys, &e.ModelElementNoParam); err != nil {
		return
	}
	out = e
	if tt, ok := elementTypes[e.Controller]; ok {
		out = reflect.New(reflect.TypeOf(tt)).Interface()
	}
	//如果是bill，则用modelelementbill
	if c := FindController(e.Controller); c == nil {
		LOG.Panic(e.Controller, "not found")
	} else if c.Bill {
		out = &modelBillElement{}
	}
	err = yaml.Unmarshal(bys, out)
	return
}
func init() {
	RegisterModel(modelElement{}, 3, false, ModelElementName)
	RegisterInstitutionModel(DeptRoot, ModelElementName,
		"owner=0 and dept in ({{P .User.ToRootDeptCodesAndSelf}})", "", "")
}
