// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package migrate

import (
	"os"

	"log"
	"github.com/lifei6671/mindoc/models"
	"container/list"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

var (
	migrationList = &migrationCache{ }
)


type MigrationDatabase interface {
	//获取当前的版本
	Version() int64
	//校验当前是否可更新
	ValidUpdate(version int64) error
	//校验并备份表结构
	ValidForBackupTableSchema() error
	//校验并更新表结构
	ValidForUpdateTableSchema() error
	//恢复旧数据
	MigrationOldTableData() error
	//插入新数据
	MigrationNewTableData() error
	//增加迁移记录
	AddMigrationRecord(version int64) error
	//最后的清理工作
	MigrationCleanup() error
	//回滚本次迁移
	RollbackMigration() error
}

type migrationCache struct {
	items *list.List
}

func RunMigration() {

	if len(os.Args) >= 2 && os.Args[1] == "migrate" {

		migrate,err := models.NewMigration().FindFirst()

		if err != nil {
			//log.Fatalf("migrations table %s", err)
			migrate = models.NewMigration()
		}
		fmt.Println("Start migration databae... ")

		for el := migrationList.items.Front(); el != nil ; el = el.Next() {

			//如果存在比当前版本大的版本，则依次升级
			if item,ok := el.Value.(MigrationDatabase); ok && item.Version() > migrate.Version {
				err := item.ValidUpdate(migrate.Version)
				if err != nil {
					log.Fatal(err)
				}
				err = item.ValidForBackupTableSchema()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.ValidForUpdateTableSchema()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.MigrationOldTableData()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.MigrationNewTableData()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.AddMigrationRecord(item.Version())
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
				err = item.MigrationCleanup()
				if err != nil {
					item.RollbackMigration()
					log.Fatal(err)
				}
			}
		}
		fmt.Println("Migration successfull.")
		os.Exit(0)
	}
}

//导出数据库的表结构
func ExportDatabaseTable()  ([]string,error) {
	db_adapter := beego.AppConfig.String("db_adapter")
	db_database := beego.AppConfig.String("db_database")
	tables := make([]string,0)

	o := orm.NewOrm()
	switch db_adapter {
	case "mysql":{
		var lists []orm.Params

		_,err := o.Raw(fmt.Sprintf("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '%s'",db_database)).Values(&lists)
		if err != nil {
			return tables,err
		}
		for _,table := range lists {
			var results []orm.Params

			_,err = o.Raw(fmt.Sprintf("show create table %s",table["TABLE_NAME"])).Values(&results)
			if err != nil {
				return tables,err
			}
			tables = append(tables,results[0]["Create Table"].(string))
		}
		break;
	}
	case "sqlite3": {
		var results []orm.Params
		_,err := o.Raw("SELECT sql FROM sqlite_master WHERE sql IS NOT NULL ORDER BY rootpage ASC").Values(&results)
		if err != nil {
			return tables,err
		}
		for _,item := range results {
			if sql,ok := item["sql"]; ok {
				tables = append(tables,sql.(string))
			}
		}
		break
	}

	}
	return tables,nil
}

func RegisterMigration()  {
	migrationList.items = list.New()

	 migrationList.items.PushBack(NewMigrationVersion03())
}