package main

import (
	"bytes"
	"crypto/x509"
	"encoding/json"
	"math/big"
	"reflect"
	"time"

	//"encoding/json"
	"encoding/pem"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"strconv"
)

type GXHCC struct {
}

type AuthGroup struct {
	Users map[string]int64 `json:"users"` //用户组权限，默认使用用户组。我们使用形如：“User1”:timestamp. key 表示用户或者角色，value 表示有效时间。我们使用格林威治时间时间戳
	Roles map[string]int64 `json:"roles"` //角色组权限，
}

type Auth struct {
	Read  AuthGroup `json:"read"`  // 字段的读权限,“”,不存在权限，
	Write AuthGroup `json:"write"` //字段的写权限
}

type LeadgerAuth struct { // 账本数据除了读权限外
	Read     AuthGroup `json:"read"`     // 字段的读权限,“”,不存在权限，
	Issue    AuthGroup `json:"issue"`    //账本数据的发行权限，
	Extract  AuthGroup `json:"extrate"`  //账本数据的提取权限，
	Transfer AuthGroup `json:"transfer"` // 账本数据的转账权限，
}

type SchemaParameters struct {
	Value  interface{} `json:"val"` //默认值  这里特别说明一下如果这里是backUp 字段，我们不进行更深一步的校验，包括格式
	PAuth  Auth        `json:"auth"`
	FCheck *Checks     `json:"fcheck"`
}

type SchemaLeadgerParameters struct {
	Value  interface{} `json:"val"` //默认值  这里特别说明一下如果这里是backUp 字段，我们不进行更深一步的校验，包括格式
	PAuth  LeadgerAuth `json:"auth"`
	FCheck *Checks     `json:"fcheck"`
}

type Checks struct {
	FType    string `json:"ftype"`    //字段类型
	Must     bool   `json:"must"`     //是否必填
	Fieldlen int    `json:"fieldlen"` //字段长度（如果字段类型是string,表示字段长度，如果是数值类型用0,1表示数据正负）
}

type Schema struct {
	LeadgerFields map[string]SchemaLeadgerParameters `json:"leadger_fields"` //账本字段
	StorageFields map[string]SchemaParameters        `json:"storage_fields"` //存证字段
	SchemaAuth    Auth                               `json:"schema_auth"`    //schema 的写权限，主要是用在 schema update 部分
	SAuth         Auth                               `json:"auth"`           //数据总的读权限
}

type Action struct {
	AccountType  string      `json:"account_type"`  //账户类型
	AccountId    string      `json:"account_id"`    //账户Id
	ActionAmount string      `json:"action_amount"` //这次的动作金额
	FundType     string      `json:"fund_type"`     //资金类型
	BackUp       interface{} `json:"back_up"`       //备注信息
}

type TransferAccount struct {
	AccountType string `json:"account_type"` //账户类型
	AccountId   string `json:"account_id"`   //账户Id
	FundType    string `json:"fund_type"`    //资金类型
}
type Node struct {
	Key   string
	Value *Schema
	pre   *Node
	next  *Node
}

type LRUCache struct {
	limit   int
	HashMap map[string]*Node
	head    *Node
	end     *Node
}

type Merchantsale struct {
	Mid         string  `json:"mid"`         //商户Id
	Bid         string  `json:"bid"`         // 分支机构id,也是一笔交易的接受者
	Tamount     string  `json:"tamount"`     //交易金额
	Treposit    string  `json:"treposit"`    //扣除预付金
	Bereposit   string  `json:"bereposit"`   //扣除前预付金
	Afreposit   string  `json:"afreposit"`   //扣除后预付金
	Feerate     float64 `json:"feerate"`     // 手续费扣率
	Free        string  `json:"free"`        // 手续费
	Oamount     string  `json:"oamount"`     // 原始交易金额
	Adiscounts  float64 `json:"adiscounts"`  //代理结算折扣
	Sdiscounts  float64 `json:"sdiscounts"`  //消费折扣
	Nodisamount string  `json:"nodisamount"` //不打折金额
	Disamount   string  `json:"disamount"`   //打折金额
	Perquisites string  `json:"perquisites"` //额外收益
}

type OrderTx struct {
	Oamount      string         `json:"oamount"` // 原始交易金额
	Pamount      string         `json:"pamount"` // 支付金额
	Odesc        *OrderDescribe `json:"odesc"`   //订单描述
	Mid          string         `json:"mid"`     //商户Id
	Norate       float64        `json:"norate"`  //无预付金收益率
	Outfree      string         `json:"outfree"` //付款方手续费
	Infree       string         `json:"infree"`  //收款方手续费
	Partnersfree string         `json:"partnersfree"` //订单合作方手续费
	Free         string         `json:"free"` // 手续费
	Pid			 string			`json:"pid"`  //合作方Id
}

type OrderDescribe struct {
	Codes      []string `json:"codes"`       //码
	TicketType int      `json:"ticket_type"` //券类型，折扣券只能使用一次
	Tid        string   `json:"tid"`         //券Id
}

type CommonTx struct {
	SenderAccountType   string `json:"sender_account"`
	SenderId            string `json:"sender_id"`
	SenderFunt          string `json:"sender_funt"`
	ReceiverAccountType string `json:"receiver_account"`
	ReceiverId          string `json:"receiver_id"`
	ReceiverFunt        string `json:"receiver_funt"`
	Amount              string `json:"amount"`
}

type transferTypes func(args []string, stub shim.ChaincodeStubInterface) error                                                                       // 声明了一个函数类型
type putDataFilter func(putDatas []map[string]interface{}, name, tableName string, schema *Schema, stub shim.ChaincodeStubInterface) (string, error) // 声明了一个函数类型,这个函数类型主要是用于putdata 数据过滤使用

var (
	defValue         = "***" //查询用户权限不足的情况下默认返回值
	StoragePrefix    = "SGXH"
	LeadgerPrefix    = "LGXH"
	IsUsers          = true        //是否启用用户权限，false 表示启用Roles
	GxhSchema        = "gxhSchema" //schema 存储前缀，为了实现复合主键使用。
	InitSchemaLength = 12          //缓存的 schema 的长度
	schemaCache      = Constructor(InitSchemaLength)
	updateTime       = int64(60 * 60 * 12) //schema 更新时间间隔，默认是12小时
	lastTime         = int64(0)
	transferType     = initTransfer()
	PutDataFilter    = initPutData()
)

// Init does nothing for this cc
func (t *GXHCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success([]byte("gxhcc init successful! "))
}

/*
	初始化我们要使用的交易执行方法
*/
func initTransfer() map[string]transferTypes {
	transferType := make(map[string]transferTypes)
	transferType["merchants"] = merchantsale
	transferType["tickerorders"] = tickerorders
	transferType["commontx"] = normalTransfer
	return transferType
}

func initPutData() map[string]putDataFilter {
	filter := make(map[string]putDataFilter)
	filter["couticketcodes"] = codeFilter
	filter["commonput"] = commanFilter
	filter["coutcantm"] = ticketMerFilter
	return filter
}

/*
	处理缓存内容的方法，
*/
func initSchema(stub shim.ChaincodeStubInterface) error {
	timeStamp, err := stub.GetTxTimestamp()
	if err != nil {
		return err
	} else if timeStamp.GetSeconds() < lastTime+updateTime {
		return nil
	}
	var values map[string]*Schema
	values = make(map[string]*Schema)

	schemaIterator, err := stub.GetStateByPartialCompositeKey(GxhSchema, nil)
	if err != nil {
		return err
	}
	defer schemaIterator.Close()
	index := 1
	for schemaIterator.HasNext() {
		querykv, err := schemaIterator.Next()
		if err != nil {
			return err
		}
		fmt.Println("add cache key:", querykv.Key)
		_, compisiteKeys, err := stub.SplitCompositeKey(querykv.Key)
		if err != nil {
			return err
		}
		scema := &Schema{}
		err = json.Unmarshal(querykv.Value, scema)
		if err != nil {
			fmt.Sprintf("json unmarshal %s schema fail,err: %s \n", querykv.Key, err)
		}
		if schemaCache.Get(compisiteKeys[0]) != nil {
			schemaCache.Put(compisiteKeys[0], scema)
			fmt.Println("add cache key:", querykv.Key)
			index++
			if index > InitSchemaLength {
				fmt.Println("cache data length :", len(schemaCache.HashMap))
				return nil
			}
		} else {
			values[compisiteKeys[0]] = scema
		}
	}
	for len(schemaCache.HashMap) < InitSchemaLength {
		for k, v := range values {
			schemaCache.Put(k, v)
		}
	}
	fmt.Println("cache data length :", len(schemaCache.HashMap))
	lastTime = timeStamp.GetSeconds() //设置最新修改时间
	return nil
}

// Invoke for this chaincode exposes
func (t *GXHCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	// get arguments and transient
	functionName, args := stub.GetFunctionAndParameters()
	var err error
	err = initSchema(stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	var res string
	switch functionName {
	case "schema":
		res, err = SchemaProcess(args, stub)
		if err != nil {
			return shim.Error(fmt.Sprintf("schema process function err: %s", err))
		}
	case "put":
		res, err = put(args, stub)
		if err != nil {
			return shim.Error(fmt.Sprintf("put function err: %s", err))
		}
	case "update":
		res, err = updateStoreData(args, stub)
		if err != nil {
			return shim.Error(fmt.Sprintf("up store data function err: %s", err))
		}
	case "get":
		res, err = get(args, stub)
		if err != nil {
			return shim.Error(fmt.Sprintf("get function err: %s", err))
		}
	case "createTx":
		res, err = transactionProcess(args, stub)
		if err != nil {
			return shim.Error(fmt.Sprintf("transaction process function err: %s", err))
		}
	case "getCertCommonName":
		res, err = getCertificateCommonName(stub)
		if err != nil {
			return shim.Error(fmt.Sprintf("get certificate common_name fail,err: %s", err))
		}
		res = "current user certificate common_name is:" + res
	default:
		return shim.Error(fmt.Sprintf("Unsupported function %s", functionName))
	}
	return shim.Success([]byte("gxhcc invoke successful:" + res))
}


func put(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) < 2 {
		return "", fmt.Errorf("put data operation expected more than 2 parameters! ")
	}
	var PutDatas []map[string]interface{}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	schema := &Schema{}
	err, schema = schema.get(args[0], stub)
	if err != nil {
		return "", err
	}
	if ok, err := authorityCheck(schema.SAuth.Write, commonName, ""); !ok {
		return "", fmt.Errorf("write %s table fail,err: %s ", args[0], err)
	}
	if err := json.Unmarshal([]byte(args[1]), &PutDatas); err != nil {
		return "", fmt.Errorf("%s table parameters Unmarshal fail,put string not json array, err:%s", args[0], err)
	}
	if len(schema.LeadgerFields) != 0 {
		return createAccount(args[0],PutDatas,schema,stub)
	}else{
		return putData(args[0], 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 := SchemaCheck(schema, mapres)
		if err != nil {
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tablename, err)
		}
		if err := FiledsCheck(schema, mapres); err != nil {
			return "", err
		}
		storagemap, leadgermap := separateFields(schema, mapres, []string{"id", "common_name"})
		storageDate, _ := json.Marshal(storagemap)
		leadgerDate, _ := json.Marshal(leadgermap)
		key := StoragePrefix + "_" + tablename + "_" + Id.(string)
		getResult, err := stub.GetState(key)
		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 := stub.PutState(key, storageDate); err != nil {
			return "", fmt.Errorf("PutState fail, err :%s", err)
		}
		if err := stub.PutState(LeadgerPrefix+"_"+tablename+"_"+Id.(string), leadgerDate); err != nil {
			return "", fmt.Errorf("PutState fail, err :%s", err)
		}
	}
	return fmt.Sprintf("create %s account success!", tablename), nil
}

///*
//	存储数据，某些不产生账本数据的数据使用这个接口来存储。例如码数据，进件表数据
//
//*/
//func putData(args []string, stub shim.ChaincodeStubInterface) (string, error) {
//	if len(args) < 2 {
//		return "", fmt.Errorf("put data operation expected more than 2 parameters! ")
//	}
//	var PutDatas []map[string]interface{}
//	commonName, err := getCertificateCommonName(stub)
//	if err != nil {
//		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
//	}
//	schema := &Schema{}
//	err, schema = schema.get(args[0], stub)
//	if err != nil {
//		return "", err
//	}
//	if ok, err := authorityCheck(schema.SAuth.Write, commonName, ""); !ok {
//		return "", fmt.Errorf("write %s table fail,err: %s ", args[0], err)
//	}
//	if err := json.Unmarshal([]byte(args[1]), &PutDatas); err != nil {
//		return "", fmt.Errorf("%s table parameters Unmarshal fail,put string not json array, err:%s", args[0], err)
//	}
//	//存储过滤器
//	_, err = filterByput(args[0], PutDatas, commonName, schema, stub)
//	if err != nil {
//		return "", err
//	}
//
//	return fmt.Sprintf("%s put data success!", args[0]), nil
//}

/*
	修改一个账户的存储数据，修改规则由Schema 控制,有些特殊数据在账本数据也使用，所以无法修改
*/
func updateStoreData(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) != 2 {
		return "", fmt.Errorf("update data operation expected 2 parameters! ")
	}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	schema := &Schema{}
	err, schema = schema.get(args[0], stub)
	if err != nil {
		return "", err
	}
	var Updata map[string]interface{}
	if err := json.Unmarshal([]byte(args[1]), &Updata); err != nil {
		return "", fmt.Errorf("%s table parameters Unmarshal fail,err: %s", args[0], 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 ")
	}
	if ok, _ := authorityCheck(schema.SAuth.Write, commonName, ""); !ok {
		if ok, err := parsauthorityCheck(schema.StorageFields, Updata, commonName); !ok {
			return "", fmt.Errorf("authority Check err: %s", err)
		}
	}
	if err := FiledsCheck(schema, Updata); err != nil {
		return "", err
	}
	key := StoragePrefix + "_" + args[0] + "_" + Id.(string)
	allMap, err := getState(key, stub)
	if 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!", args[0]), nil
}

/*
	查询数据，如果存在账本数据，与存证数据，则进行数据拼接，然后返回。
*/
func get(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) != 2 {
		return "", fmt.Errorf("get data operation expected  2 parameters to function get!")
	}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	var parameters map[string]interface{}
	json.Unmarshal([]byte(args[1]), &parameters)
	if err != nil {
		return "", fmt.Errorf("parameters Unmarshal fail,err: %s", err)
	}

	Id, ok := parameters["id"]
	if !ok {
		return "", fmt.Errorf("The id field must exist ")
	}
	storageKey := StoragePrefix + "_" + args[0] + "_" + Id.(string)
	mapResult, err := getState(storageKey, stub)
	if err != nil {
		return "", err
	}
	leadgerKey := LeadgerPrefix + "_" + args[0] + "_" + Id.(string)
	leadgerResult, err := stub.GetState(leadgerKey)
	if err != nil {
		return "", fmt.Errorf("get %s data fail,please check your parameters ", leadgerKey)
	}
	schema := &Schema{}
	err, schema = schema.get(args[0], 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 ok, _ := authorityCheck(schema.SAuth.Read, commonName, ""); !ok {
		if filteredData, err := dataFilter(schema, 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
	}
}

func SchemaProcess(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) < 2 {
		return "", fmt.Errorf("Expect features with 2 or more parameters to play! ")
	}
	schema := &Schema{}
	switch args[0] {

	case "put":
		return schema.put(args[1:], stub)
	case "update":
		return schema.update(args[1:], stub)
	case "get":
		return schema.getSchema(args[1], stub)

	default:
		return "", fmt.Errorf(fmt.Sprintf("Unsupported schema function of %s", args[0]))

	}
	return "", nil
}
func transactionProcess(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) < 2 {
		return "", fmt.Errorf("Expect features with 2 or more parameters to play! ")
	}
	switch args[0] {

	case "issue": //进行账户金额发行（无中生有）
		return funtOperation(args[1:], stub, true)
	case "extract": //提取账户金额（直接减去）
		return funtOperation(args[1:], stub, false)
	case "transfer": // 一笔普通转账
		return transferTx(args[1:], stub)
	default:
		return "", fmt.Errorf(fmt.Sprintf("Unsupported schema function of %s", args[0]))

	}
	return "", nil
}

/*
	put
	args 字段说明：
	1：args[0]代表我们具体操作的表，
    2：args[1:]后面的数据表示要记录到数据库的数据,每一个string 必须是json字符串，并且需要每一个json 字符串都必须包含id 字段

我们可以发现json字符串都被我们解析成了map[string]interface{}类型的map,其中key代表表模板的字段，interface可以是一个结构，我们当前将他看做我们表模板字段的初始值。
伪代码：
1：在创建schema data 时，我们必须检查金额字段的类型必须是float64,并且不能为负数。
*/
func (this *Schema) put(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) != 2 {
		return "", fmt.Errorf("Schema  put operation expected  2 parameters!")
	}
	var schema *Schema
	var err error
	if schema, err = NewSchema(args[1]); err != nil {
		return "", fmt.Errorf("The parameters Unmarshal to a Schema structural fail,err: %s ", err)
	} else {
		if backupValue, ok := schema.StorageFields["backup"]; ok {
			if _, ok := backupValue.Value.(map[string]interface{}); !ok {
				return "", fmt.Errorf("backup parameters Unmarshal fail,it not json string,err: %s", err)
			}
		}
	}
	_, ok := schema.StorageFields["id"]
	if !ok {
		return "", fmt.Errorf("The id field must exist ")
	}
	_, ok = schema.StorageFields["common_name"]
	if !ok {
		return "", fmt.Errorf("The common_name field must exist ")
	}

	CompositeKey, err := stub.CreateCompositeKey(GxhSchema, []string{args[0]})
	if err != nil {
		return "", fmt.Errorf("the schema %s create comosite key fail,err : %s", args[0], err)
	}
	if schemaCache.Get(args[0]) != nil {
		return "", fmt.Errorf("the schema %s already exists and cannot be added", args[0])
	} else if value, _ := stub.GetState(CompositeKey); value != nil {
		return "", fmt.Errorf("the schema %s already exists and cannot be added", args[0])
	}
	putDate, _ := json.Marshal(schema) //处理重复字段
	if err := stub.PutState(CompositeKey, putDate); err != nil {
		return "", fmt.Errorf("Schema PutState fail,err: %s ", err)
	}
	schemaCache.Put(args[0], schema)
	return fmt.Sprintf("%s schema put success!", args[0]), nil
}

/*
	if update Schema 那么我们没有办法比较旧有的一个模板，
     Schema 的 update,不支持部分修改，因为存在增加和删除某些字段的情况。
     初版暂时只允许修改存储数据,金额字段暂时不允许修改
*/
func (this *Schema) update(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	if len(args) != 2 {
		return "", fmt.Errorf("Schema update operation expected 2 parameters! ")
	}
	var schema *Schema
	schemaOld := &Schema{}
	var err error
	if schema, err = NewSchema(args[1]); err != nil {
		return "", fmt.Errorf("The parameters Unmarshal to a Schema structural fail,err: %s ", err)
	} else {
		if backupValue, ok := schema.StorageFields["backup"]; ok {
			if _, ok := backupValue.Value.(map[string]interface{}); !ok {
				return "", fmt.Errorf("backup parameters Unmarshal fail,it not json string,err: %s", err)
			}
		}
	}
	_, ok := schema.StorageFields["id"]
	if !ok {
		return "", fmt.Errorf("The id field must exist ")
	}
	_, ok = schema.StorageFields["common_name"]
	if !ok {
		return "", fmt.Errorf("The common_name field must exist ")
	}
	CompositeKey, err := stub.CreateCompositeKey(GxhSchema, []string{args[0]})
	if err != nil {
		return "", fmt.Errorf("the schema %s create comosite key fail,err : %s", args[0], err)
	}
	err, schemaOld = schemaOld.get(args[0], stub)
	if err != nil {
		return "", err
	}
	//if err := json.Unmarshal(result, &schemaOld); err != nil {
	//	return "", fmt.Errorf("The parameters Unmarshal to a Schema structural fail, err: %s ", err)
	//}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	if ok, err := authorityCheck(schemaOld.SchemaAuth.Write, commonName, ""); !ok {
		return "", fmt.Errorf("update %s schema fail,err: %s ", args[0], err)
	}
	schema.LeadgerFields = schemaOld.LeadgerFields
	updateData, _ := json.Marshal(schema)
	if err = stub.PutState(CompositeKey, updateData); err != nil {
		return "", fmt.Errorf("%s schema data PutState fail,please try again ", args[0])
	}
	return fmt.Sprintf("%s schema update success!", args[0]), err

}

func (this *Schema) get(args string, stub shim.ChaincodeStubInterface) (error, *Schema) {
	schema := &Schema{}
	var result []byte
	if schema = schemaCache.Get(args); schema == nil {
		CompositeKey, err := stub.CreateCompositeKey(GxhSchema, []string{args})
		if err != nil {
			return fmt.Errorf("the schema %s create comosite key fail,err : %s", args, err), nil
		}
		result, err = stub.GetState(CompositeKey)
		if err != nil || result == nil {
			return fmt.Errorf("%s schema data doesn't exist,please check your parameters ", args), nil
		}
		if err := json.Unmarshal(result, schema); err != nil {
			return fmt.Errorf("SchemaData Unmarshal fail, err: %s", err), nil
		}
		schemaCache.Put(args, schema)
	}
	return nil, schema
}

func (this *Schema) getSchema(args string, stub shim.ChaincodeStubInterface) (string, error) {
	schema := &Schema{}
	var result []byte
	if schema = schemaCache.Get(args); schema == nil {
		CompositeKey, err := stub.CreateCompositeKey(GxhSchema, []string{args})
		if err != nil {
			return "", fmt.Errorf("the schema %s create comosite key fail,err : %s", args, err)
		}
		result, err := stub.GetState(CompositeKey)
		if err != nil || result == nil {
			return "", fmt.Errorf("%s schema data doesn't exist,please check your parameters ", args)
		}
		if err := json.Unmarshal(result, schema); err != nil {
			return "", fmt.Errorf("SchemaData Unmarshal fail, err: %s", err)
		}
		schemaCache.Put(args, schema)

	} else {
		result, _ = json.Marshal(schema)
	}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	if ok, err := authorityCheck(this.SchemaAuth.Read, commonName, ""); !ok {
		return "", fmt.Errorf("get %s schema fail,err: %s", args, err)
	}
	return string(result), nil
}

func transferTx(args []string, stub shim.ChaincodeStubInterface) (string, error) {
	txFunc := transferType[args[0]]
	if txFunc == nil {
		return "", fmt.Errorf("No matching transfer operation method was found ! ")
	}
	err := txFunc(args[1:], stub)
	if err != nil {
		return "", fmt.Errorf("%s transfer operation fail,err:%s ", args[0], err)
	}
	return "", 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 = SchemaCheck(schema, mapres)
		if err != nil {
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tableName, err)
		}
		if err := FiledsCheck(schema, mapres); err != nil {
			return "", 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 := SchemaCheck(schema, mapres)
		if err != nil {
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tableName, err)
		}
		if err := FiledsCheck(schema, mapres); err != nil {
			return "", 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 ")
		}
		if len(schema.LeadgerFields) != 0 {
			return "", fmt.Errorf("%s schema exist leadger fields,cannot putData", tableName)
		}
		err := SchemaCheck(schema, mapres)
		if err != nil {
			return "", fmt.Errorf("args index %d string, %s schema cheack fail,err : %s ", k, tableName, err)
		}
		if err := FiledsCheck(schema, mapres); err != nil {
			return "", err
		}
		key := StoragePrefix + "_" + tableName + "_" + mid.(string) + "_" + tid.(string)
		err = putState(key, mapres, stub)
		if err != nil {
			return "", err
		}
	}
	return "", nil
}

func SchemaCheck(schema *Schema, checkmap map[string]interface{}) error {
	if len(schema.StorageFields)+len(schema.LeadgerFields) != len(checkmap) {
		return fmt.Errorf("The input field length is less than the schema field length ! ")
	}
	for k, v := range schema.StorageFields {
		if schemaV, ok := checkmap[k]; !ok {
			return fmt.Errorf("There is no input storage field %s ", k)
		} else {
			if parameterS, ok := v.Value.(map[string]interface{}); ok {
				if parameterC, ok := schemaV.(map[string]interface{}); !ok {
					return fmt.Errorf("The input field %s does not match the output field format ", k)
				} else {
					err := BackUpCheck(parameterS, parameterC)
					if err != nil {
						return err
					}
				}
			}
		}
	}
	for k, _ := range schema.LeadgerFields {
		if _, ok := checkmap[k]; !ok {
			return fmt.Errorf("There is no input leadger field %s ", k)
		}
	}
	return nil
}

func FiledsCheck(schema *Schema, checkmap map[string]interface{}) error {
	for k, schemaV := range schema.StorageFields {
		if k != "backup" && schemaV.FCheck != nil && schemaV.FCheck.FType != "" && checkmap[k] != nil {
			if err := fieldCheckout(schemaV.FCheck, checkmap[k]); err != nil {
				return fmt.Errorf("%s %s ", k, err)
			}
		}
	}
	for k, schemaV := range schema.LeadgerFields {
		if schemaV.FCheck != nil && schemaV.FCheck.FType != "" && checkmap[k] != nil {
			if err := fieldCheckout(schemaV.FCheck, checkmap[k]); err != nil {
				return fmt.Errorf("%s %s ", k, err)
			}
		}
	}
	return nil
}

func BackUpCheck(backUp map[string]interface{}, checkmap map[string]interface{}) error {
	if len(backUp) != len(checkmap) {
		return fmt.Errorf("The input backup field length is less than the schema backup field length ! ")
	}
	for k, _ := range checkmap {
		if _, ok := backUp[k]; !ok {
			return fmt.Errorf("There is no input backup field %s ", k)
		}
	}
	return nil
}

/*
	将字段根据账本数据，与存储数据分开
	leadgers:参数表示我们需要在账本数据包含的字段，这些字段不属于账本数据。
*/
func separateFields(schema *Schema, checkmap map[string]interface{}, leadgers []string) (storagemap, leadgermap map[string]interface{}) {
	storagemap = make(map[string]interface{})
	leadgermap = make(map[string]interface{})
	for k, _ := range schema.LeadgerFields {
		leadgermap[k] = checkmap[k]
	}
	for _, v := range leadgers {
		leadgermap[v] = checkmap[v]
	}
	for k, _ := range schema.StorageFields {
		storagemap[k] = checkmap[k]
	}
	return
}

/*
	根据权限拼装数据,进行数据过滤
*/
func dataFilter(schema *Schema, checkmap map[string]interface{}, commonName, onwer string) (map[string]interface{}, error) {
	for k, schemaV := range schema.StorageFields {
		if v, ok := checkmap[k]; !ok {
			return nil, fmt.Errorf("Update data parameter mismatch with schema structure! ")
		} else {
			if _, ok := schemaV.Value.(map[string]SchemaParameters); ok {
				if _, ok := v.(map[string]interface{}); !ok {
					return nil, fmt.Errorf("Update data parameter mismatch with schema structure! ")
				}
				if ok, _ := authorityCheck(schemaV.PAuth.Read, commonName, onwer); !ok {
					checkmap[k] = defValue
				}
			} else {
				if ok, _ := authorityCheck(schemaV.PAuth.Read, commonName, onwer); !ok {
					checkmap[k] = defValue
				}
			}
		}
	}
	for k, schemaV := range schema.LeadgerFields {
		if v, ok := checkmap[k]; !ok {
			return nil, fmt.Errorf("Update data parameter mismatch with schema structure! ")
		} else {
			if _, ok := schemaV.Value.(map[string]SchemaLeadgerParameters); ok {
				if _, ok := v.(map[string]interface{}); !ok {
					return nil, fmt.Errorf("Update data parameter mismatch with schema structure! ")
				}
				if ok, _ := authorityCheck(schemaV.PAuth.Read, commonName, onwer); !ok {
					checkmap[k] = defValue
				}
			} else {
				if ok, _ := authorityCheck(schemaV.PAuth.Read, commonName, onwer); !ok {
					checkmap[k] = defValue
				}
			}
		}
	}
	return checkmap, nil
}

func authorityCheck(authority AuthGroup, commonName, owner string) (bool, error) {
	var auths map[string]int64
	if IsUsers {
		auths = authority.Users
	} else {
		auths = authority.Roles
	}
	if len(auths) == 0 {
		return true, nil
	}
	for k, v := range auths {
		if k == commonName || (k == "owner" && commonName == owner) {
			if v == 0 || v > time.Now().Unix() {
				return true, nil
			} else {
				return false, fmt.Errorf("%s user permission period ", commonName)
			}
		}
	}
	return false, fmt.Errorf("%s user does not have permission", commonName)

}

/*
	检查一组参数的权限是否匹配
*/
func parsauthorityCheck(schema map[string]SchemaParameters, checkmap map[string]interface{}, commonName string) (bool, error) {
	for k, v := range checkmap {
		if schemaV, ok := schema[k]; !ok {
			return false, fmt.Errorf("Update data parameter mismatch with schema structure! ")
		} else {
			if _, ok := schemaV.Value.(map[string]interface{}); ok {
				if _, ok := v.(map[string]interface{}); !ok {
					return false, fmt.Errorf("Update data parameter mismatch with schema structure! ")
				}
			}
			if ok, err := authorityCheck(schemaV.PAuth.Write, commonName, ""); !ok {
				return false, fmt.Errorf("%s field permission check does not match, err: %s ", k, err)
			}
		}
	}
	return true, nil
}

/*
	重新赋值，并检查相应的格式是否正确
*/
func Deassign(upMap, result map[string]interface{}) error {
	if len(upMap) > len(result) {
		return fmt.Errorf("Deassign fail,reassigned data length greater than the original data length! ")
	}
	for k, v := range upMap {
		if resultV, ok := result[k]; ok {
			if resultMap, resultok := resultV.(map[string]interface{}); resultok {
				if vMap, ok := v.(map[string]interface{}); !ok {
					return fmt.Errorf("Deassign fail, format doesn't match! ")
				} else {
					Deassign(vMap, resultMap)
				}
			} else {
				result[k] = v
			}
		} else {
			return fmt.Errorf("Deassign fail %s key nonentity ", k)
		}
	}
	return nil
}

/*
	账户金额发现，核心是在对应的schema 找到有发行的权利。
	1：金额字段也就是（账本字段数据）都有发行标示
	2：发行交易可以存在多个字段，但只要保证我们要求的字段存在就可以。账户类型，Id，发行金额（大于0）
*/
func funtOperation(args []string, stub shim.ChaincodeStubInterface, isIssue bool) (string, error) {
	if len(args) != 1 {
		return "", fmt.Errorf("issue or extract  operation expected 1 parameters ! ")
	}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return "", fmt.Errorf("getCertificateCommonName happen err: %s ", err)
	}
	action := &Action{}
	err = json.Unmarshal([]byte(args[0]), action)
	if err != nil {
		return "", fmt.Errorf("json unmarshal Action structure fail,err: %s", err)
	}
	schema := &Schema{}
	err, schema = schema.get(action.AccountType, stub)
	if err != nil {
		return "", err
	}
	leadgerKey := LeadgerPrefix + "_" + action.AccountType + "_" + action.AccountId
	leadgermap, err := getState(leadgerKey, stub)
	if err != nil {
		return "", err
	}
	onwer, ok := leadgermap["common_name"].(string)
	if isIssue {
		if ok, err := authorityCheck(schema.LeadgerFields[action.FundType].PAuth.Issue, commonName, onwer); !ok {
			return "", fmt.Errorf("%s field issue permission check does not match, err: %s ", action.FundType, err)
		}
	} else {
		if ok, err := authorityCheck(schema.LeadgerFields[action.FundType].PAuth.Extract, commonName, onwer); !ok {
			return "", fmt.Errorf("%s field extract permission check does not match, err: %s ", action.FundType, err)
		}
	}
	funt, ok := leadgermap[action.FundType].(string)
	funtAmount, ok := new(big.Int).SetString(funt, 10)
	if !ok {
		return "", fmt.Errorf("%s parameter resolution to big.int failed ", action.FundType)
	}
	actionAmount, ok := new(big.Int).SetString(action.ActionAmount, 10)
	if !ok {
		return "", fmt.Errorf("action_amount parameter resolution to big.int failed ")
	}
	sum := new(big.Int)
	if isIssue {
		sum = sum.Add(funtAmount, actionAmount)
	} else {
		if funtAmount.Cmp(actionAmount) == -1 {
			return "", fmt.Errorf("The current amount is less than the withdrawal amount and cannot be extracted ")
		}
		sum = sum.Sub(funtAmount, actionAmount)
	}
	leadgermap[action.FundType] = sum.String()
	leadgerResult, _ := json.Marshal(leadgermap)

	err = stub.PutState(leadgerKey, leadgerResult)
	if err != nil {
		return "", fmt.Errorf("putState %s data fail,err: %s", leadgerKey, err)
	}
	return "transaction successful!", nil
}

/*

 */
func normalTransfer(args []string, stub shim.ChaincodeStubInterface) error {
	if len(args) != 1 {
		return nil
	}
	tx := &CommonTx{}
	err := json.Unmarshal([]byte(args[0]), tx)
	if err != nil {
		fmt.Errorf("CommonTx structure json unmarshal fail,err : %s ", err)
	}
	sender := &TransferAccount{
		tx.SenderAccountType,
		tx.SenderId,
		tx.SenderFunt,
	}
	receiver := &TransferAccount{
		tx.ReceiverAccountType,
		tx.ReceiverId,
		tx.ReceiverFunt,
	}
	commonName, err := getCertificateCommonName(stub)
	if err != nil {
		return nil
	}
	amount, ok := new(big.Int).SetString(tx.Amount, 10)
	if !ok {
		return fmt.Errorf("amount parameter resolution to big.int failed ")
	}
	return transfer(amount, sender, receiver, commonName, stub)
}

/*
	当增加一条交易记录的时候，我们需要根据交易记录实现，
1.预付金的计算，2.计算分成，3.预付金的变化。分成的计算
*/
func merchantsale(args []string, stub shim.ChaincodeStubInterface) error {
	commanName, err := getCertificateCommonName(stub)
	if err != nil {
		return err
	}
	senderaccountType := "merchants"
	receiverAccountType := "alibusi"
	mer := &Merchantsale{}
	err = json.Unmarshal([]byte(args[0]), mer)
	if err != nil {
		return fmt.Errorf("Merchantsale struct json unmarshal fail,err : %s ", err)
	}
	sender := &TransferAccount{
		senderaccountType,
		mer.Mid,
		"regular",
	}
	receiver := &TransferAccount{
		receiverAccountType,
		mer.Bid,
		"abail",
	}

	rtreposit, ok := new(big.Int).SetString(mer.Treposit, 10)
	if !ok {
		return fmt.Errorf("Treposit parameter resolution to big.int failed ")
	}
	//errinfo := make(chan error)
	err = transfer(rtreposit, sender, receiver, commanName, stub)
	if err != nil {
		return err
	}
	//1.计算预付金 这部分待定
	treposit := new(big.Int)
	nodisamount, ok := new(big.Int).SetString(mer.Nodisamount, 10)
	if !ok {
		return fmt.Errorf("Nodisamount parameter resolution to big.int failed ")
	}
	disamount, ok := new(big.Int).SetString(mer.Disamount, 10)
	if !ok {
		return fmt.Errorf("Disamount parameter resolution to big.int failed ")
	}
	oamount, ok := new(big.Int).SetString(mer.Oamount, 10)
	if !ok {
		return fmt.Errorf("Oamount parameter resolution to big.int failed ")
	}
	if nodisamount.Cmp(big.NewInt(0)) == 0 || disamount.Cmp(big.NewInt(0)) == 0 { //如果打折金额与不打折金额任一为0，则认为全部打折
		treposit, err = dividecalc(oamount, mer.Adiscounts)
		if err != nil {
			return err
		}
	} else {
		distre, err := dividecalc(disamount, mer.Adiscounts) //计算打折部分的金额
		if err != nil {
			return err
		}
		treposit = new(big.Int).Add(nodisamount, distre)
	}

	if treposit.Cmp(rtreposit) != 0 {
		return fmt.Errorf("treposit calculation fail ")
	}

	rfee, ok := new(big.Int).SetString(mer.Free, 10)
	if !ok {
		return fmt.Errorf("Fee parameter resolution to big.int failed ")
	}
	tamount, ok := new(big.Int).SetString(mer.Tamount, 10)
	if !ok {
		return fmt.Errorf("Tamount parameter resolution to big.int failed ")
	}
	fee, err := dividecalc(tamount, mer.Feerate)
	if err != nil {
		return err
	}
	if fee.Cmp(rfee) != 0 {
		return fmt.Errorf("fee calculation fail ")
	}
	profit := new(big.Int).Sub(tamount, new(big.Int).Add(rfee, rtreposit)) //计算分成
	if profit.Cmp(big.NewInt(0)) == -1 {
		return fmt.Errorf("profit is negative ")
	}

	//进行分成数据
	err = dividesTransaction(mer.Mid,treposit,stub)
	if err!= nil{
		return err
	}
	return err
}

/*
	共享惠订单交易
*/
func tickerorders(args []string, stub shim.ChaincodeStubInterface) error {
	/*
		由于共享惠还没有进行确定的订单交易所以这部分先进行伪代码的记录
			1：计算实际支付是否正确，
			2：计算手续费总和是否正确
			3：计算利润
			4：是否需要进行商户金额的清分（待定）//待办
			5：合作方分成
			6：最终分成
	*/
	//commanName, err := getCertificateCommonName(stub)
	//if err != nil {
	//	return err
	//}
	ticketcanName := "coutcantm"
	ticketName := "coutickets"
	codeName := "couticketcodes"
	oTx := &OrderTx{}
	err := json.Unmarshal([]byte(args[0]), oTx)
	if err != nil {
		return fmt.Errorf("OrderTx struct json unmarshal fail,err : %s ", err)
	}
	tickMerKey := StoragePrefix + "_" + ticketcanName + "_" + oTx.Mid + "_" + oTx.Odesc.Tid  //券可用门店key
	tickM, err := getState(tickMerKey, stub)
	if err != nil {
		return err
	}
	tickKey := StoragePrefix + "_" + ticketName +"_" + oTx.Odesc.Tid  //券key
	tick, err := getState(tickKey, stub)
	if err != nil {
		return err
	}
	resid, _ := tickM["resid"].(float64)  //剩余可用码数
	discount, _ := tick["discount"].(float64) //得到券面值
	fieldkeys := []string{"status"}  // 码状态
	var checkvalue, upvalue []interface{}
	if resid == 0 {
		return fmt.Errorf("The current merchant has been unable to use the %s ticket ", oTx.Odesc.Tid)
	}
	oamount,ok := new(big.Int).SetString(oTx.Oamount,10)
	if !ok {
		return fmt.Errorf("Oamount parameter resolution to big.int failed ")
	}
	pamount,ok := new(big.Int).SetString(oTx.Pamount,10)
	if !ok {
		return fmt.Errorf("Pamount parameter resolution to big.int failed ")
	}
	outfree,ok := new(big.Int).SetString(oTx.Outfree,10)
	if !ok {
		return fmt.Errorf("Outfree parameter resolution to big.int failed ")
	}
	infree,ok := new(big.Int).SetString(oTx.Infree,10)
	if !ok {
		return fmt.Errorf("Infree parameter resolution to big.int failed ")
	}
	partnersfree,ok := new(big.Int).SetString(oTx.Partnersfree,10)
	if !ok {
		return fmt.Errorf("Partnersfree parameter resolution to big.int failed ")
	}
	free,ok := new(big.Int).SetString(oTx.Free,10)
	if !ok {
		return fmt.Errorf("Free parameter resolution to big.int failed ")
	}
	if oTx.Odesc.TicketType == 1 { //如果是折扣券则只能使用一张券
		if len(oTx.Odesc.Codes) > 1 {
		return 	fmt.Errorf("Only one coupon can be used ")
		}
		codeKey := StoragePrefix + "_" + codeName + "_" + oTx.Odesc.Codes[0]
		checkvalue[0] = float64(1)
		upvalue[0] = float64(2)
		_,err = checkandUpdate(codeKey,fieldkeys,checkvalue,upvalue,stub)
		if err != nil {
			return err
		}
		camount,_ :=  dividecalc(oamount,discount)
		if camount.Cmp(pamount) != 0{
			return fmt.Errorf("pamount calculation fail ")
		}
	} else {
		for i, v := range oTx.Odesc.Codes {
			codeKey := StoragePrefix + "_" + codeName + "_" + v
			checkvalue[i] = float64(1)
			upvalue[i] = float64(2)
			_,err = checkandUpdate(codeKey,fieldkeys,checkvalue,upvalue,stub)
			if err != nil {
				return err
			}
		}
		length := int64(len(oTx.Odesc.Codes))
		disint := int64(discount) //将discount 转化为整数
		camount := new(big.Int).Sub(oamount,big.NewInt(disint*length))
		if camount.Cmp(pamount) != 0{
			return fmt.Errorf("pamount calculation fail ")
		}
	}
	cfree := new(big.Int).Add(new(big.Int).Add(outfree,infree),partnersfree)
	if free.Cmp(cfree) != 0{
		return fmt.Errorf("free calculation fail ")
	}
	income := new(big.Int).Sub(pamount,free)
	treposit,err := dividecalc(income,oTx.Norate)
	if err != nil{
		return err
	}
	receiver := &TransferAccount{
		AccountType:"coupartners",
		AccountId:oTx.Pid,
		FundType:"benefit",
	}
	err = transfer(partnersfree,nil,receiver,"",stub)
	if err!= nil{
		return err
	}
	//netincome := new(big.Int).Sub(income,treposit)
	err = dividesTransaction(oTx.Mid,treposit,stub)
	if err!= nil{
		return err
	}
	return nil
}

/*
	根据商户Id,进行分成交易
*/
func dividesTransaction(mid string,treposit *big.Int,stub shim.ChaincodeStubInterface)error{
	merkey := StoragePrefix+ "_" + "merchants" + "_" + mid
	mermap,err := getState(merkey,stub)
	if err != nil{
		return err
	}
	aid,ok := mermap["aid"].(string)  //得到代理商Id
	if !ok {
		return fmt.Errorf("aid parameter resolution to string failed ")
	}
	bid,ok := mermap["bid"].(string)  //得到分支机构Id
	if !ok {
		return fmt.Errorf("Free parameter resolution to string failed ")
	}
	acid,ok := mermap["acid"].(string)  //得到加盟商Id
	if !ok {
		return fmt.Errorf("Free parameter resolution to string failed ")
	}
	fid,ok := mermap["fid"].(string)   //得到保理
	if !ok {
		return fmt.Errorf("Free parameter resolution to string failed ")
	}
	asdiscounts ,err := divide(aid,treposit,stub)
	if err != nil{
		return err
	}
	bsdiscounts ,err := divide(bid,treposit,stub)
	if err != nil{
		return err
	}
	acsdiscounts ,err := divide(acid,treposit,stub)
	if err != nil{
		return err
	}
	fsdiscounts ,err := divide(fid,treposit,stub)
	if err != nil{
		return err
	}
	if asdiscounts+bsdiscounts+acsdiscounts+fsdiscounts > 1 {
		return fmt.Errorf("The divide proportion must not exceed 1 ")
	}
	return nil
}

func divide(id string,treposit *big.Int,stub shim.ChaincodeStubInterface)(float64,error){
	akey := StoragePrefix+ "_" + "alibusi" + "_" + id
	amap,err := getState(akey,stub)
	if err != nil{
		return 0,err
	}
	sdiscounts,ok := amap["sdiscounts"].(float64)
	if !ok {
		return 0,fmt.Errorf("sdiscounts parameter resolution to float64 failed ")
	}
	adivide,err := dividecalc(treposit,sdiscounts)
	if err != nil{
		return 0, err
	}
	areceiver := &TransferAccount{
		AccountType:"alibusi",
		AccountId:id,
		FundType:"amount",
	}

	return sdiscounts,transfer(adivide,nil,areceiver,"",stub)
}
/*
	特别说明interface 不能是引用类型
*/
func checkandUpdate(key string, fieldkeys []string, checkvalue, upvalue []interface{}, stub shim.ChaincodeStubInterface)(map[string]interface{},error ){
	valueMap, err := getState(key, stub)
	if err != nil {
		return nil,err
	}
	for i, fk := range fieldkeys {
		if !reflect.DeepEqual(valueMap[fk], checkvalue[i]) {
			return nil, fmt.Errorf("%s not the expected field value",fk)
		} else {
			valueMap[fk] = upvalue[i]
		}
	}
	value, err := json.Marshal(valueMap)
	if err != nil {
		return nil, err
	}
	err = stub.PutState(key, value)
	if err != nil {
		return nil, err
	}

	return valueMap, nil
}

/*
	实现普通的转账操作
*/
func transfer(amount *big.Int, sender, receiver *TransferAccount, commonName string, stub shim.ChaincodeStubInterface) error {
	var err error
	if amount.Cmp(big.NewInt(0)) == -1 {
		err = fmt.Errorf("transfer limit must greater than 0 ")
		return err
	}
	if sender != nil {
		senderSchema := &Schema{}
		err, senderSchema = senderSchema.get(sender.AccountType, stub)
		if err != nil {
			return err
		}
		senderKey := LeadgerPrefix + "_" + sender.AccountType + "_" + sender.AccountId
		senderleadgermap, err := getState(senderKey, stub)
		if err != nil {
			return err
		}
		onwer, ok := senderleadgermap["common_name"].(string)
		if ok, err := authorityCheck(senderSchema.LeadgerFields[sender.FundType].PAuth.Transfer, commonName, onwer); !ok {
			err = fmt.Errorf("%s field issue permission check does not match, err: %s ", sender.FundType, err)
			return err
		}
		fundstr := senderleadgermap[sender.FundType].(string)
		fund, ok := new(big.Int).SetString(fundstr, 10)
		if !ok {
			err = fmt.Errorf("%s parameter resolution to big.int failed ", sender.FundType)
			return err
		}
		if fund.Cmp(amount) == -1 {
			err = fmt.Errorf("The current amount is less than the withdrawal amount and cannot be extracted ")
			return err
		}
		fund.Sub(fund, amount)
		senderleadgermap[sender.FundType] = fund.String()

		err = putState(senderKey, senderleadgermap, stub)
		if err != nil {
			return err
		}
	}
	if receiver != nil {
		receiverKey := LeadgerPrefix + "_" + receiver.AccountType + "_" + receiver.AccountId
		receiverleadgermap, err := getState(receiverKey, stub)
		if err != nil {
			return err
		}
		rfundstr := receiverleadgermap[receiver.FundType].(string)
		rfund, ok := new(big.Int).SetString(rfundstr, 10)
		if !ok {
			err = fmt.Errorf("%s parameter resolution to big.int failed ", receiver.FundType)
			return err
		}
		rfund.Add(rfund, amount)
		receiverleadgermap[receiver.FundType] = rfund.String()

		err = putState(receiverKey, receiverleadgermap, stub)
		if err != nil {
			return err
		}
	}
	return nil
}

func getState(key string, stub shim.ChaincodeStubInterface) (map[string]interface{}, error) {
	var resultmap map[string]interface{}
	result, err := stub.GetState(key)
	if err != nil {
		return nil, fmt.Errorf("GetState %s data fail,err %s ", key, err)
	}
	if result == nil {
		return nil, fmt.Errorf("GetState %s data is null,please check your parameters ", key)
	}
	err = json.Unmarshal(result, &resultmap)
	if err != nil {
		return nil, fmt.Errorf("json unmarshal leadger map fail,err: %s", err)
	}
	return resultmap, nil
}

func putState(key string, value map[string]interface{}, stub shim.ChaincodeStubInterface) error {
	valueByte, err := json.Marshal(value)
	if err != nil {
		return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
	}
	err = stub.PutState(key, valueByte)
	if err != nil {
		return fmt.Errorf("putState %s data fail,err: %s", key, err)
	}
	return nil
}

func getCertificateCommonName(stub shim.ChaincodeStubInterface) (string, error) {
	return "Admin@org2.example.com", nil
	creatorByte, _ := stub.GetCreator()
	certStart := bytes.IndexAny(creatorByte, "-----BEGIN")
	if certStart == -1 {
		return "", fmt.Errorf("No certificate found ")
	}
	certText := creatorByte[certStart:]
	bl, _ := pem.Decode(certText)
	if bl == nil {
		return "", fmt.Errorf("Could not decode the PEM structure ")
	}
	cert, err := x509.ParseCertificate(bl.Bytes)
	if err != nil {
		return "", fmt.Errorf("ParseCertificate failed")
	}
	return cert.Subject.CommonName, nil
}

func Decimal(value float64) float64 {
	value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64)
	return value
}

func NewSchema(arg string) (*Schema, error) {
	schema := &Schema{
		LeadgerFields: make(map[string]SchemaLeadgerParameters),
		StorageFields: make(map[string]SchemaParameters),
	}
	var argMap map[string]interface{}
	if err := json.Unmarshal([]byte(arg), &argMap); err != nil {
		return nil, err
	}
	if (argMap["storage_fields"] != nil || argMap["leadger_fields"] != nil) && argMap["schema_auth"] != nil && argMap["auth"] != nil {
		if err := json.Unmarshal([]byte(arg), schema); err != nil {
			return nil, err
		}
		//检查schema leadger字段
		err := leadgerFieldsCheck(&schema.LeadgerFields)
		if err != nil {
			return nil, err
		}
		return schema, nil
	}
	for k, v := range argMap { //假设用户只传递了map类型的信息，我们则默认它全部都是存储字段
		schema.StorageFields[k] = SchemaParameters{
			Value: v,
			PAuth: Auth{},
		}
	}
	return schema, nil
}

func leadgerFieldsCheck(leadgerFields *map[string]SchemaLeadgerParameters) error {
	for k, fields := range *leadgerFields {
		if fields.FCheck == nil {
			fields.FCheck = &Checks{
				FType:    "big.int",
				Must:     false,
				Fieldlen: 1,
			}
		} else {
			if fields.FCheck.FType != "big.int" {
				return fmt.Errorf("%s fields type must is big.int", k)
			} else if !(fields.FCheck.Fieldlen > 0) {
				return fmt.Errorf("%s fields length must is greater than zero", k)
			}
		}
		if len(fields.PAuth.Extract.Roles) == 0 && len(fields.PAuth.Extract.Users) == 0 {

		}
	}
	return nil
}

func fieldCheckout(check *Checks, val interface{}) error {
	fType := reflect.TypeOf(val).String()

	switch check.FType {
	case "string":
		if fType != "string" {
			return fmt.Errorf("fields type does not match the defined string type! ")
		}
		if check.Must && (val == "") {
			return fmt.Errorf("fields can not be empty")
		}
		value := val.(string)
		if len([]rune(value)) > check.Fieldlen {
			return fmt.Errorf("fields length cannot be greater than %d ", check.Fieldlen)
		}
	case "int", "int16", "int32", "int64", "float32", "float64":
		if fType != "float64" {
			return fmt.Errorf("fields type does not match the defined %s type! ", check.FType)
		}
		value := val.(float64)
		if check.Must && (value == 0) {
			return fmt.Errorf("fields can not be 0")
		}
		if check.Fieldlen != 0 && value < 0 {
			return fmt.Errorf("fields cannot be negative")
		}
	case "time.Time":
		if fType != "string" {
			return fmt.Errorf("fields type does not match the defined time.Time type! ")
		}
		dateStr := reflect.ValueOf(val).String()
		if check.Must && dateStr == "" {
			return fmt.Errorf("fields cannot be empty")
		}
		if _, err := time.Parse("2006-01-02 15:04:05", dateStr); err != nil {
			return fmt.Errorf(err.Error())
		}

		//if check.Must && (dateStr == "0001-01-01 00:00:00 +0000 UTC"|| dateStr == "0001-01-01T00:00:00Z"){
		//	return fmt.Errorf("fields cannot be initial value")
		//}
	case "big.int":
		if fType != "string" {
			return fmt.Errorf("fields type does not match the defined big.int type! ")
		}
		number := new(big.Int)
		dateStr := reflect.ValueOf(val).String()
		_, ok := number.SetString(dateStr, 10)
		if !ok {
			return fmt.Errorf("parameter resolution failed ")
		}
	default:
		fmt.Errorf("fields type no match! ")
	}
	return nil
}

func Constructor(capacity int) LRUCache {
	lruCache := LRUCache{limit: capacity}
	lruCache.HashMap = make(map[string]*Node, capacity)
	return lruCache
}

func (l *LRUCache) Get(key string) *Schema {
	if v, ok := l.HashMap[key]; ok {
		l.refreshNode(v)
		return v.Value
	} else {
		return nil
	}
}

func (l *LRUCache) Put(key string, value *Schema) error {
	if v, ok := l.HashMap[key]; !ok {
		if len(l.HashMap) >= l.limit {
			oldKey := l.removeNode(l.head)
			delete(l.HashMap, oldKey)
		}
		node := Node{Key: key, Value: value}
		l.addNode(&node)
		l.HashMap[key] = &node
	} else {
		v.Value = value
		l.refreshNode(v)
	}
	return nil
}

func (l *LRUCache) refreshNode(node *Node) {
	if node == l.end {
		return
	}
	l.removeNode(node)
	l.addNode(node)
}

func (l *LRUCache) removeNode(node *Node) string {
	if node == l.end {
		l.end = l.end.pre
		l.end.next = nil
	} else if node == l.head {
		l.head = l.head.next
		l.head.pre = nil
	} else {
		node.pre.next = node.next
		node.next.pre = node.pre
	}
	return node.Key
}

func (l *LRUCache) addNode(node *Node) {
	if l.end != nil {
		l.end.next = node
		node.pre = l.end
		node.next = nil
	}
	l.end = node
	if l.head == nil {
		l.head = node
	}
}

func dividecalc(bint *big.Int, divide float64) (*big.Int, error) {
	divide *= 1000000
	value := new(big.Int).Mul(bint, big.NewInt(int64(divide)))
	value.Div(value, big.NewInt(1000000))
	return value, nil
}

func main() {
	err := shim.Start(&GXHCC{})
	if err != nil {
		fmt.Printf("Error starting EncCC chaincode: %s", err)
	}
}
