//pragma solidity >=0.6.10 <0.8.20;
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import "../Table.sol";
import "./Utils.sol";
import "./CreateTable.sol";

contract Provider {
    event CreateResult(int256 count);
    event InsertResult(int256 count);
    event UpdateResult(int256 count);
    event RemoveResult(int256 count);
    

    struct ProviderData{
        string  table_prefix;
        string  name;
        string  addr;
        int256  create_time;
        int256  update_time;
        string  status;//valid invalid
        int256 update_data_time;
    }
    Utils utils = new Utils();
    CreateTable createTable = new CreateTable();
    TableFactory tableFactory;
    string constant TABLE_NAME = "provider_20240607_1";
    string constant KEY_NAME = "key";
    string constant KEY_VALUE = "key";
    constructor() public {
        tableFactory = TableFactory(0x1001); //The fixed address is 0x1001 for TableFactory
        // the parameters of createTable are tableName,keyField,"vlaueFiled1,vlaueFiled2,vlaueFiled3,..."
        //创建表
        tableFactory.createTable(TABLE_NAME, KEY_NAME, "table_prefix,name,addr,create_time,update_time,status,update_data_time");
    }
    
    
    //插入，只能自己插入自己的
    function insert(string memory table_prefix,string memory name,int256 create_time,int256 update_time) 
    public 
    returns(int256,string memory){
        if(existByName(name) || existByPrefix(table_prefix)){
            return (0,"name and table_prefix not repeat");
        }
        Table table = tableFactory.openTable(TABLE_NAME);
        Condition condition = table.newCondition();
        condition.EQ("addr", utils.toString(tx.origin));
        Entries entries = table.select(KEY_VALUE, condition);
        if(entries.size()>0){
            revert("you address have register one provider, can not repeat regester");
        }
        
        Entry entry = table.newEntry();
        entry.set(KEY_NAME, KEY_VALUE);
        entry.set("table_prefix", table_prefix);
        entry.set("name", name);
        entry.set("addr", utils.toString(tx.origin));
        entry.set("create_time", create_time);
        entry.set("update_time", update_time);
        entry.set("status", "valid");
        entry.set("update_data_time",create_time);//默认设置为与本记录的创建时间相同
        
        //创建附属表
        createTable.create(table_prefix);

        int256 count = table.insert(KEY_VALUE, entry);
        if(count>0){
            emit InsertResult(count);
        }
        return (count,"success");
    }
    
    
    function select()
    public
    view
    returns (ProviderData[] memory){
        Table table = tableFactory.openTable(TABLE_NAME);

        Condition condition = table.newCondition();
        
        Entries entries = table.select(KEY_VALUE, condition);
        uint256  dataLen =   uint256(entries.size());
        ProviderData[] memory pArray = new ProviderData[](dataLen);

        for (uint256 i = 0; i < dataLen; ++i) {
            Entry entry = entries.get(int256(i));
            pArray[i]=ProviderData(entry.getString("table_prefix"),entry.getString("name"),entry.getString("addr"),entry.getInt("create_time"),entry.getInt("update_time"),entry.getString("status"),entry.getInt("update_data_time"));

        }
        
        return (pArray);
    }
    
    
    function selectMySelf()
    public
    view
    returns (ProviderData[] memory){
        Table table = tableFactory.openTable(TABLE_NAME);

        Condition condition = table.newCondition();
        condition.EQ("addr", utils.toString(tx.origin));
        Entries entries = table.select(KEY_VALUE, condition);
        uint256  dataLen =   uint256(entries.size());
        ProviderData[] memory pArray = new ProviderData[](dataLen);

        for (uint256 i = 0; i < dataLen; ++i) {
            Entry entry = entries.get(int256(i));
            pArray[i]=ProviderData(entry.getString("table_prefix"),entry.getString("name"),entry.getString("addr"),entry.getInt("create_time"),entry.getInt("update_time"),entry.getString("status"),entry.getInt("update_data_time"));

        }
        
        return (pArray);

    }
    
    
    //更新数据的更新时间，在上传或者更新了自身的目录数据之后调用，便于利用方在恰当时间发起查询链上目录数据的请求
    function updateData(int256 update_data_time)
    public
    returns (int256,string memory)
    {
        Table table = tableFactory.openTable(TABLE_NAME);

        
        Entry entry = table.newEntry();
        entry.set("update_data_time",update_data_time);
        entry.set("update_time",update_data_time);
        Condition condition = table.newCondition();
        condition.EQ("addr", utils.toString(tx.origin));

        int256 count = table.update(KEY_VALUE, entry, condition);
        if(count>0){
            emit UpdateResult(count);
        }
        return (count,"success");
    }
    
    
    
    //修改名称
    function updateName(string memory name,int256 update_time)
    public
    returns (int256,string memory)
    {
        if(utils.strIsEmpty(name)){
            return (0,"name not empty");
        }
        if(update_time == 0){
            return (0,"update_time not empty");
        }
        Table table = tableFactory.openTable(TABLE_NAME);
        //检查名称是否重复
        if(existByName(name)){
            return (0,"Name already exists");
        }
        
        Entry entry = table.newEntry();
        entry.set("name",name);
        entry.set("update_time",update_time);

        Condition condition = table.newCondition();
        condition.EQ("addr", utils.toString(tx.origin));

        int256 count = table.update(KEY_VALUE, entry, condition);
        if(count>0){
            emit UpdateResult(count);
        }

        return (count,"success");
    }
    
     //根据机构名称删除
    function remove() 
    public 
    returns (int256) {
        Table table = tableFactory.openTable(TABLE_NAME);

        Condition condition = table.newCondition();
        condition.EQ("addr", utils.toString(tx.origin));

        int256 count = table.remove(KEY_VALUE, condition);
        if(count>0){
            emit RemoveResult(count);
        }
        
        return count;
    }
    
    
    //根据name判定是否存在
    function existByName(string memory name)
    public
    view
    returns (bool){
        Table table = tableFactory.openTable(TABLE_NAME);
        Condition condition = table.newCondition();
        condition.EQ("name", name);
        Entries entries = table.select(KEY_VALUE, condition);
        return entries.size()>0;
    }
    //根据table_prefix判定是否存在
    function existByPrefix(string memory table_prefix)
    public
    view
    returns (bool){
        Table table = tableFactory.openTable(TABLE_NAME);
        Condition condition = table.newCondition();
        condition.EQ("table_prefix", table_prefix);
        Entries entries = table.select(KEY_VALUE, condition);
        return entries.size()>0;
    }
    
    
    //根据地址查找机构的表前缀
    function selectPrefixByAddr(string addr)
    public
    view
    returns (string memory){
        Table table = tableFactory.openTable(TABLE_NAME);
        Condition condition = table.newCondition();
        condition.EQ("addr",addr);
        Entries entries = table.select(KEY_VALUE, condition);
        if(entries.size()>0){
            Entry entry = entries.get(int256(0));
            return entry.getString("table_prefix");
        }
        revert("caller need regerest as a provider");
    }
    
}