contract DiagonICO is DiagonToken {

    address public admin;
    address payable public deposit;
    FiatContract public fiatPrice;
    
    // Token price: 1DGN = 0.2 USD
    uint public tokenPrice;
    uint public psTokenPrice;
    
    uint public hardCap;
    
    uint public raisedAmount;
    
    uint public saleStart = 1568628000;
    
    uint public saleEnd = 1582588799;
    
    uint public coinTradeStart = saleEnd; // Tokens transferable in a week after salesEnd
    
    uint public maxInvestment;
    uint public minInvestment;
    
    
    enum State { beforeStart, running, afterEnd, halted }
    State public icoState;
    
    modifier onlyAdmin() {
        require(msg.sender == admin);
        _;
    }
    
    event Invest(address investor, uint value, uint tokens);
    
    constructor(address payable _deposit) public {
        deposit = _deposit;
        admin = msg.sender;
        fiatPrice = FiatContract(0x8055d0504666e2B6942BeB8D6014c964658Ca591);

        uint256 ethCent = fiatPrice.USD(0);

        tokenPrice = ethCent * 20;
        hardCap = ethCent * 450000000;
        maxInvestment = ethCent * 450000000;
        minInvestment = ethCent * 2000;

        icoState = State.beforeStart;
    }

    function tokenBalance() public view returns (uint) {
        return (balances[msg.sender]);
    }

    function erc20Address() public view returns (address) {
        address erc20Adr = msg.sender;
        return erc20Adr;
    }
    
    // ICO Emergency Stop
    function halt() public onlyAdmin {
        icoState = State.halted;
    }
    
    // Restart ICO
    function unhalt() public onlyAdmin{
        icoState = State.running;
    }
    
    function changeDepositAddress(address payable newDeposit) public onlyAdmin {
        deposit = newDeposit;
    }
    
    function getCurrentState() public view returns(State) {
        if(icoState == State.halted) {
            return State.halted;
        }else if(block.timestamp < saleStart){
            return State.beforeStart;
        } else if(block.timestamp >= saleStart && block.timestamp <= saleEnd){
            return State.running;
        } else {
            return State.afterEnd;
        }
    }
    
    function invest() payable public returns(bool){
        // Invest only in ICO running state
        icoState = getCurrentState();
        
        require(icoState == State.running);
        
        require(msg.value >= minInvestment && msg.value <= maxInvestment);
        
        uint tokens = msg.value / tokenPrice;

        // HardCap not reached
        require(raisedAmount + msg.value <= hardCap);

        raisedAmount += msg.value;
    
        // Add tokens to investor's balance from founder balance
        balances[msg.sender] += tokens;
        balances[founder] -= tokens;
    
        deposit.transfer(msg.value); // Transfer ETH to the deposit address
    
        emit Invest(msg.sender, msg.value, tokens);
    
        return true;
    }
    
    // Burning all unsold token
    function burn() public returns(bool){
        require(msg.sender == admin);
        icoState = getCurrentState();
        require(icoState == State.afterEnd);
        balances[founder] = 0;
    }
    
    // Invest function from an external address
    function () payable external {
        invest();
    }
    
    function transfer(address to, uint value) public returns(bool){
        if (block.timestamp < coinTradeStart) {
            require(msg.sender == admin);
            super.transfer(to, value);
        } else {
            require(block.timestamp > coinTradeStart);
            super.transfer(to, value);
        }
    }
    
    function transferFrom(address _from, address _to, uint _value) public returns(bool){
        require(block.timestamp > coinTradeStart);
        super.transferFrom(_from, _to, _value);
    }
}
function burn() public returns(bool){
    require(msg.sender == admin);
    icoState = getCurrentState();
    require(icoState == State.afterEnd);
    balances[founder] = 0;
}

// Burning all unsold token