contract SlognToken is Token, EscrowICO {
    string public constant STANDARD = 'Slogn v0.1';
    string public constant NAME = 'SLOGN';
    string public constant SYMBOL = 'SLGN';
    uint8 public constant PRECISION = 14;

    uint256 public constant TOTAL_SUPPLY = 800000 ether; // initial total supply equals to 8.000.000.000 slogns or 800.000 eths

    uint256 public constant CORE_TEAM_TOKENS = TOTAL_SUPPLY / 100 * 15;       // 15%
    uint256 public constant ADVISORY_BOARD_TOKENS = TOTAL_SUPPLY / 1000 * 15;       // 1.5%
    uint256 public constant OPENSOURCE_TOKENS = TOTAL_SUPPLY / 1000 * 75;     // 7.5%
    uint256 public constant RESERVE_TOKENS = TOTAL_SUPPLY / 100 * 5;          // 5%
    uint256 public constant BOUNTY_TOKENS = TOTAL_SUPPLY / 100;               // 1%

    address public advisoryBoardFundManager;
    address public opensourceFundManager;
    address public reserveFundManager;
    address public bountyFundManager;
    address public ethFundManager;
    address public owner;

    /* This generates a public event on the blockchain that will notify clients */
    event BonusEarned(address target, uint256 bonus);

    /* Modifiers */
    modifier onlyOwner() {
        require(owner == msg.sender);

        _;
    }

    /* Initializes contract with initial supply tokens to the creator of the contract */
    function SlognToken(
    address [] coreTeam,
    address _advisoryBoardFundManager,
    address _opensourceFundManager,
    address _reserveFundManager,
    address _bountyFundManager,
    address _ethFundManager
    )
    Token (TOTAL_SUPPLY, STANDARD, NAME, SYMBOL, PRECISION)
    EscrowICO()
    {
        owner = msg.sender;

        advisoryBoardFundManager = _advisoryBoardFundManager;
        opensourceFundManager = _opensourceFundManager;
        reserveFundManager = _reserveFundManager;
        bountyFundManager = _bountyFundManager;
        ethFundManager = _ethFundManager;

        // transfer tokens to core team
        uint256 tokensPerMember = CORE_TEAM_TOKENS / coreTeam.length;

        for(uint8 i = 0; i < coreTeam.length; i++) {
            transferInternal(this, coreTeam[i], tokensPerMember);
        }

        // Advisory board fund
        transferInternal(this, advisoryBoardFundManager, ADVISORY_BOARD_TOKENS);

        // Opensource fund
        transferInternal(this, opensourceFundManager, OPENSOURCE_TOKENS);

        // Reserve fund
        transferInternal(this, reserveFundManager, RESERVE_TOKENS);

        // Bounty fund
        transferInternal(this, bountyFundManager, BOUNTY_TOKENS);
    }

    function buyFor(address _user, uint256 ethers, uint time) internal returns (bool success) {
        require(ethers > 0);

        uint8 icoStep = getIcoStep(time);

        require(icoStep == 1 || icoStep == 2);

        // maximum collected amount for preico is 5000 ether
        if(icoStep == 1 && (totalSoldSlogns + ethers) > 5000 ether) {
            throw;
        }

        uint256 slognAmount = ethers; // calculates the amount

        uint256 bonus = calculateBonus(icoStep, totalSoldSlogns, slognAmount);

        // check for available slogns
        require(balanceOf[this] >= slognAmount + bonus);

        if(bonus > 0) {
            BonusEarned(_user, bonus);
        }

        transferInternal(this, _user, slognAmount + bonus);

        totalSoldSlogns += slognAmount;

        if(icoStep == 1) {
            preIcoEthers[_user] += ethers;      // fill ethereum used for refund if goal not reached
        }
        if(icoStep == 2) {
            icoEthers[_user] += ethers;      // fill ethereum used for refund if goal not reached
        }

        return true;
    }

    /**
     * Buy Slogn tokens
     */
    function buy() payable {
        buyFor(msg.sender, msg.value, block.timestamp);
    }

    /**
     * Manage ethereum balance
     * @param to The address to transfer to.
     * @param value The amount to be transferred.
     */
    function transferEther(address to, uint256 value) returns (bool success) {
        if(msg.sender != ethFundManager) {
            return false;
        }

        if(totalSoldSlogns < MIN_PRE_ICO_SLOGN_COLLECTED) {
            return false;
        }

        if(this.balance < value) {
            return false;
        }

        to.transfer(value);

        return true;
    }

    /**
     * Transfer token for a specified address
     * @param _to The address to transfer to.
     * @param _value The amount to be transferred.
     */
    function transfer(address _to, uint256 _value) returns (bool success) {
        if(isTransactionsAllowed == false) {
            if(msg.sender != bountyFundManager) {
                return false;
            }
        }

        return transferInternal(msg.sender, _to, _value);
    }

    /**
     * Transfer tokens from one address to another
     * @param _from address The address which you want to send tokens from
     * @param _to address The address which you want to transfer to
     * @param _value uint256 the amout of tokens to be transfered
     */
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if(isTransactionsAllowed == false) {
            if(_from != bountyFundManager) {
                return false;
            }
        }

        return transferFromInternal(_from, _to, _value);
    }

    function refund() returns (bool) {
        return refundInternal(block.timestamp);
    }

    function icoFinish() returns (bool) {
        return icoFinishInternal(block.timestamp);
    }

    function setPreIcoDates(uint256 since, uint256 till) onlyOwner {
        PRE_ICO_SINCE = since;
        PRE_ICO_TILL = till;
    }

    function setIcoDates(uint256 since, uint256 till) onlyOwner {
        ICO_SINCE = since;
        ICO_TILL = till;
    }

    function setTransactionsAllowed(bool enabled) onlyOwner {
        isTransactionsAllowed = enabled;
    }

    function () payable {
        throw;
    }
}
function transferEther(address to, uint256 value) returns (bool success) {
    if(msg.sender != ethFundManager) {
        return false;
    }

    if(totalSoldSlogns < MIN_PRE_ICO_SLOGN_COLLECTED) {
        return false;
    }

    if(this.balance < value) {
        return false;
    }

    to.transfer(value);

    return true;
}

/**
 * Manage ethereum balance
 * @param to The address to transfer to.
 * @param value The amount to be transferred.
 */