package main

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
)


func put(tablename string,PutDatas []map[string]interface{}, stub shim.ChaincodeStubInterface) (string, error) {
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	schema := &Schema{}
	schema ,err  = getSchema(tablename, stub)
	if err != nil {
		return "", err
	}
	if  err := schema.AllWriteCheck( commonName, ""); err != nil {
		return "", fmt.Errorf("write %s table fail,err: %s ", tablename, err)
	}
	if len(schema.LeadgerFields) != 0 {
		return createAccount(tablename,PutDatas,schema,stub)
	}else{
		return putData(tablename, PutDatas, commonName, schema, stub)
	}
}

/*
	根据账户类型创建账本账户，由于我们这里有存储数据与账本数据两种，所以我们还需要在schema 部分标识不同的数据类型。
	伪代码：
	1：检查当前用户是否具有账户的总写（创建）权限
	2：检查账户必备的属性，如Id,账户名，账户所属者，对应的是证书commonName
	2：根据schema 标注的金额（账本）字段，和存证字段，分别进行数据的putState存储工作。其中在存证数据的Id 字段是标示字段。
	3：完成账户创建工作
*/
func createAccount(tablename string,PutDatas []map[string]interface{},schema *Schema, stub shim.ChaincodeStubInterface) (string, error) {
	for k, mapres := range PutDatas {
		Id, ok := mapres["id"]
		if !ok {
			return "", fmt.Errorf("The id field must exist ")
		}
		_, ok = mapres["common_name"]
		if !ok {
			return "", fmt.Errorf("The common_name field must exist ")
		}
		err := schema.FieldsCheck(mapres)
		if err != nil {
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tablename, err)
		}

		storagemap, leadgermap := separateFields(schema, mapres, []string{"id", "common_name"})

		key := StoragePrefix + "_" + tablename + "_" + Id.(string)
		getResult, err := getState(key,stub)
		if err != nil {
			return "", fmt.Errorf("GetState %s data fail,please check your parameters ", key)
		}
		if getResult != nil {
			return "", fmt.Errorf("%s data already exists and cannot be added", key)
		}
		if err := putState(key, storagemap,stub); err != nil {
			return "", err
		}
		if err := putState(LeadgerPrefix+"_"+tablename+"_"+Id.(string), leadgermap,stub); err != nil {
			return "", err
		}
	}
	return fmt.Sprintf("create %s account success!", tablename), nil
}


/*
	修改一个账户的存储数据，修改规则由Schema 控制,有些特殊数据在账本数据也使用，所以无法修改
*/
func updateStoreData(tablename string,updata map[string]interface{}, stub shim.ChaincodeStubInterface) (string, error) {
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	schema := &Schema{}
	schema ,err  = getSchema(tablename, stub)
	if err != nil {
		return "", err
	}
	Id, ok := updata["id"]
	if !ok {
		return "", fmt.Errorf("The id field must exist ")
	}
	_, ok = updata["common_name"]
	if ok {
		return "", fmt.Errorf("The common_name field cannot update ")
	}

	key := StoragePrefix + "_" + tablename + "_" + Id.(string)
	allMap, err := getState(key, stub)
	if err != nil {
		return "", err
	}
	owner, ok := allMap["common_name"].(string)
	if !ok {
		return "", fmt.Errorf("common_name fields resolution failed ")
	}
	schema.AllWriteCheck(commonName, owner)
	if err != nil{
		err := schema.DataWriteCheck( updata, commonName,owner)
		if err !=nil{
			return "", err
		}
	}

	if err := schema.FieldsFormatCheck(updata); err != nil {
		return "", err
	}


	if err := Deassign(updata, allMap); err != nil {
		return "", err
	}
	err = putState(key, allMap, stub)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s update data success!",tablename), nil
}

/*
	查询数据，如果存在账本数据，与存证数据，则进行数据拼接，然后返回。
*/
func get(tablename string,parameters map[string]interface{}, stub shim.ChaincodeStubInterface) (string, error) {
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}

	Id, ok := parameters["id"]
	if !ok {
		return "", fmt.Errorf("The id field must exist ")
	}
	storageKey := StoragePrefix + "_" + tablename + "_" + Id.(string)
	mapResult, err := getState(storageKey, stub)
	if err != nil {
		return "", err
	}
	leadgerKey := LeadgerPrefix + "_" + tablename + "_" + Id.(string)
	leadgerResult, err := stub.GetState(leadgerKey)
	if err != nil {
		return "", fmt.Errorf("get %s data fail,please check your parameters ", leadgerKey)
	}
	schema := &Schema{}
	schema ,err  = getSchema(tablename, stub)
	if err != nil {
		return "", err
	}
	if leadgerResult != nil {
		if err := json.Unmarshal(leadgerResult, &mapResult); err != nil {
			return "", fmt.Errorf("The leadger original data Unmarshal fail err:%s ", err)
		}
	}
	onwer, ok := mapResult["common_name"].(string)
	if !ok {
		return "", fmt.Errorf("common_name fields resolution failed ")
	}
	if  err := schema.AllReadCheck( commonName, onwer); err != nil {
		if filteredData, err := schema.ReadFiler( mapResult, commonName, onwer); err != nil {
			return "", fmt.Errorf("get data authority filter fail, err: %s", err)
		} else {
			result, _ := json.Marshal(filteredData)
			return string(result), nil
		}

	} else {
		result, _ := json.Marshal(mapResult)
		return string(result), nil
	}
}


/*
	有些特殊的putdata 数据是存在过滤条件的，此方法就是进行过滤
*/
func putData(filterName string, putDatas []map[string]interface{}, commonName string, schema *Schema, stub shim.ChaincodeStubInterface) (string, error) {
	filterFunc := PutDataFilter[filterName]
	if filterFunc == nil {
		return "", fmt.Errorf("No matching filter operation method was found ! ")
	}
	str, err := filterFunc(putDatas, commonName, filterName, schema, stub)
	if err != nil {
		return "", fmt.Errorf("%s filter operation fail,err:%s ", filterName, err)
	}
	return str, nil
}

/*
	在共享惠项目中当用户上传码数据时，存在对发行总数控制的要求。
*/
func codeFilter(putDatas []map[string]interface{}, commonName, tableName string, schema *Schema, stub shim.ChaincodeStubInterface) (string, error) {
	sum := len(putDatas)
	if sum == 0 {
		return "", fmt.Errorf("put length cannot zero! ")
	}
	tid, ok := putDatas[0]["tid"].(string)
	if !ok {
		return "", fmt.Errorf("tid fields type must string! ")
	}
	dependData := "coutickets"
	Stkey := StoragePrefix + "_" + dependData + "_" + tid
	tmap, err := getState(Stkey, stub)
	if err != nil {
		return "", err
	}
	count, ok := tmap["surplusCount"].(float64) //剩余可发行数
	if !ok {
		return "", fmt.Errorf("surplusCount fields type must float64! ")
	}
	count -= float64(sum)
	if count >= 0 {
		tmap["surplusCount"] = count
	} else {
		return "", fmt.Errorf("The number of issues exceeds the total number of issues! ")
	}
	err = putState(Stkey, tmap, stub)
	if err != nil {
		return "", err
	}
	for k, mapres := range putDatas {
		Id, ok := mapres["id"]
		if !ok {
			return "", fmt.Errorf("The id field must exist ")
		}
		_, ok = mapres["common_name"]
		if !ok {
			return "", fmt.Errorf("The common_name field must exist ")
		}
		err = schema.FieldsCheck(mapres)
		if err != nil {
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tableName, err)
		}

		key := StoragePrefix + "_" + tableName + "_" + Id.(string)
		_, err := getState(key, stub)
		if err != nil {
			return "", err
		}
		err = putState(key, mapres, stub)
		if err != nil {
			return "", err
		}
	}
	return fmt.Sprintf("%s data save success!", tableName), nil
}

func commanFilter(putDatas []map[string]interface{}, commonName, tableName string, schema *Schema, stub shim.ChaincodeStubInterface) (string, error) {
	for k, mapres := range putDatas {
		Id, ok := mapres["id"]
		if !ok {
			return "", fmt.Errorf("The id field must exist ")
		}
		_, ok = mapres["common_name"]
		if !ok {
			return "", fmt.Errorf("The common_name field must exist ")
		}

		err := schema.FieldsFormatCheck(mapres)
		if err!= nil{
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tableName, err)
		}
		key := StoragePrefix + "_" + tableName + "_" + Id.(string)
		err = putState(key, mapres, stub)
		if err != nil {
			return "", err
		}
	}
	return fmt.Sprintf("%s data save success!", tableName), nil
}

/*
	券可用门店过滤表
*/
func ticketMerFilter(putDatas []map[string]interface{}, commonName, tableName string, schema *Schema, stub shim.ChaincodeStubInterface) (string, error) {
	for k, mapres := range putDatas {
		mid, ok := mapres["mid"]
		if !ok {
			return "", fmt.Errorf("The mid field must exist ")
		}
		tid, ok := mapres["tid"]
		if !ok {
			return "", fmt.Errorf("The tid field must exist ")
		}
		_, ok = mapres["common_name"]
		if !ok {
			return "", fmt.Errorf("The common_name field must exist ")
		}
		err := schema.FieldsFormatCheck(mapres)
		if err!= nil{
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tableName, err)
		}
		key := StoragePrefix + "_" + tableName + "_" + mid.(string) + "_" + tid.(string)
		err = putState(key, mapres, stub)
		if err != nil {
			return "", err
		}
	}
	return "", nil
}