pragma solidity ^0.4.8;


//
// FOR REFERENCE - INCLUDE  iE4RowEscrow  (interface) CONTRACT at the top .....
//

contract iE4RowEscrow {
        function getNumGamesStarted() constant returns (int ngames);
}

// Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/issues/20

// ---------------------------------
// ABSTRACT standard token class
// ---------------------------------
contract Token { 
    function totalSupply() constant returns (uint256 supply);
    function balanceOf(address _owner) constant returns (uint256 balance);
    function transfer(address _to, uint256 _value) returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    function approve(address _spender, uint256 _value) returns (bool success);
    function allowance(address _owner, address _spender) constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}


// --------------------------
//  E4RowRewards - abstract e4 dividend contract
// --------------------------
contract E4RowRewards
{
        function checkDividends(address _addr) constant returns(uint _amount);
        function withdrawDividends() public returns (uint namount);
}

// --------------------------
//  Finney Chip - token contract
// --------------------------
contract E4Token is Token, E4RowRewards {
        event StatEvent(string msg);
        event StatEventI(string msg, uint val);

        enum SettingStateValue  {debug, release, lockedRelease}
        enum IcoStatusValue {anouncement, saleOpen, saleClosed, failed, succeeded}




        struct tokenAccount {
                bool alloced; // flag to ascert prior allocation
                uint tokens; // num tokens
                uint balance; // rewards balance
        }
// -----------------------------
//  data storage
// ----------------------------------------
        address developers; // developers token holding address
        address public owner; // deployer executor
        address founderOrg; // founder orginaization contract
        address auxPartner; // aux partner (pr/auditing) - 1 percent upon close
        address e4_partner; // e4row  contract addresses


        mapping (address => tokenAccount) holderAccounts ; // who holds how many tokens (high two bytes contain curPayId)
        mapping (uint => address) holderIndexes ; // for iteration thru holder
        uint numAccounts;

        uint partnerCredits; // amount partner (e4row)  has paid
        mapping (address => mapping (address => uint256)) allowed; // approvals


        uint maxMintableTokens; // ...
        uint minIcoTokenGoal;// token goal by sale end
        uint minUsageGoal; //  num games goal by usage deadline
        uint public  tokenPrice; // price per token
        uint public payoutThreshold; // threshold till payout

        uint totalTokenFundsReceived;   // running total of token funds received
        uint public totalTokensMinted;  // total number of tokens minted
        uint public holdoverBalance;            // hold this amount until threshhold before reward payout
        int public payoutBalance;               // hold this amount until threshhold before reward payout
        int prOrigPayoutBal;                    // original payout balance before run
        uint prOrigTokensMint;                  // tokens minted at start of pay run
        uint public curPayoutId;                // current payout id
        uint public lastPayoutIndex;            // payout idx between run segments
        uint public maxPaysPer;                 // num pays per segment
        uint public minPayInterval;             // min interval between start pay run


        uint fundingStart;              // funding start time immediately after anouncement
        uint fundingDeadline;           // funding end time
        uint usageDeadline;             // deadline where minimum usage needs to be met before considered success
        uint public lastPayoutTime;     // timestamp of last payout time
        uint vestTime;          // 1 year past sale vest developer tokens
        uint numDevTokens;      // 10 per cent of tokens after close to developers
        bool developersGranted;                 // flag
        uint remunerationStage;         // 0 for not yet, 1 for 10 percent, 2 for remaining  upon succeeded.
        uint public remunerationBalance;        // remuneration balance to release token funds
        uint auxPartnerBalance;         // aux partner balance - 1 percent
        uint rmGas; // remuneration gas
        uint rwGas; // reward gas
        uint rfGas; // refund gas

        IcoStatusValue icoStatus;  // current status of ico
        SettingStateValue public settingsState;


        // --------------------
        // contract constructor
        // --------------------
        function E4Token() 
        {
                owner = msg.sender;
                developers = msg.sender;
        }

        // -----------------------------------
        // use this to reset everything, will never be called after lockRelease
        // -----------------------------------
        function applySettings(SettingStateValue qState, uint _saleStart, uint _saleEnd, uint _usageEnd, uint _minUsage, uint _tokGoal, uint  _maxMintable, uint _threshold, uint _price, uint _mpp, uint _mpi )
        {
                if (msg.sender != owner) 
                        return;

                // these settings are permanently tweakable for performance adjustments
                payoutThreshold = _threshold;
                maxPaysPer = _mpp;
                minPayInterval = _mpi;

                if (settingsState == SettingStateValue.lockedRelease)
                        return;

                settingsState = qState;
                icoStatus = IcoStatusValue.anouncement;

                rmGas = 100000; // remuneration gas
                rwGas = 10000; // reward gas
                rfGas = 10000; // refund gas


                // zero out all token holders.  
                // leave alloced on, leave num accounts
                // cant delete them anyways

                if (totalTokensMinted > 0) {
                        for (uint i = 0; i < numAccounts; i++ ) {
                                address a = holderIndexes[i];
                                if (a != address(0)) {
                                        holderAccounts[a].tokens = 0;
                                        holderAccounts[a].balance = 0;
                                }
                        }
                }
                // do not reset numAccounts!

                totalTokensMinted = 0; // this will erase
                totalTokenFundsReceived = 0; // this will erase.
                e4_partner = address(0); // must be reset again

                fundingStart =  _saleStart;
                fundingDeadline = _saleEnd;
                usageDeadline = _usageEnd;
                minUsageGoal = _minUsage;
                minIcoTokenGoal = _tokGoal;
                maxMintableTokens = _maxMintable;
                tokenPrice = _price;

                vestTime = fundingStart + (365 days);
                numDevTokens = 0;

                holdoverBalance = 0;
                payoutBalance = 0;
                curPayoutId = 1;
                lastPayoutIndex = 0;
                remunerationStage = 0;
                remunerationBalance = 0;

                auxPartnerBalance = 0;

                if (this.balance > 0) {
                        if (!owner.call.gas(rfGas).value(this.balance)())
                                StatEvent("ERROR!");
                }
                StatEvent("ok");

        }


        // ---------------------------------------------------
        // tokens held reserve the top two bytes for the payid last paid.
        // this is so holders at the top of the list dont transfer tokens 
        // to themselves on the bottom of the list thus scamming the 
        // system. this function deconstructs the tokenheld value.
        // ---------------------------------------------------
        function getPayIdAndHeld(uint _tokHeld) internal returns (uint _payId, uint _held)
        {
                _payId = (_tokHeld / (2 ** 48)) & 0xffff;
                _held = _tokHeld & 0xffffffffffff;
        }
        function getHeld(uint _tokHeld) internal  returns (uint _held)
        {
                _held = _tokHeld & 0xffffffffffff;
        }
        // ---------------------------------------------------
        // allocate a new account by setting alloc to true
        // set the top to bytes of tokens to cur pay id to leave out of current round
        // add holder index, bump the num accounts
        // ---------------------------------------------------
        function addAccount(address _addr) internal  {
                holderAccounts[_addr].alloced = true;
                holderAccounts[_addr].tokens = (curPayoutId * (2 ** 48));
                holderIndexes[numAccounts++] = _addr;
        }


// --------------------------------------
// BEGIN ERC-20 from StandardToken
// --------------------------------------
        function totalSupply() constant returns (uint256 supply)
        {
                if (icoStatus == IcoStatusValue.saleOpen
                        || icoStatus == IcoStatusValue.anouncement)
                        supply = maxMintableTokens;
                else
                        supply = totalTokensMinted;
        }

        function transfer(address _to, uint256 _value) returns (bool success) {

                if ((msg.sender == developers) 
                        &&  (now < vestTime)) {
                        //statEvent("Tokens not yet vested.");
                        return false;
                }


                //Default assumes totalSupply can't be over max (2^256 - 1).
                //If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
                //Replace the if with this one instead.
                //if (holderAccounts[msg.sender] >= _value && balances[_to] + _value > holderAccounts[_to]) {

                var (pidFrom, heldFrom) = getPayIdAndHeld(holderAccounts[msg.sender].tokens);
                if (heldFrom >= _value && _value > 0) {

                    holderAccounts[msg.sender].tokens -= _value;

                    if (!holderAccounts[_to].alloced) {
                        addAccount(_to);
                    }

                    uint newHeld = _value + getHeld(holderAccounts[_to].tokens);
                    holderAccounts[_to].tokens = newHeld | (pidFrom * (2 ** 48));
                    Transfer(msg.sender, _to, _value);
                    return true;
                } else { 
                        return false; 
                }
        }

        function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {

                if ((_from == developers) 
                        &&  (now < vestTime)) {
                        //statEvent("Tokens not yet vested.");
                        return false;
                }


        //same as above. Replace this line with the following if you want to protect against wrapping uints.
        //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {

                var (pidFrom, heldFrom) = getPayIdAndHeld(holderAccounts[_from].tokens);
                if (heldFrom >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
                    holderAccounts[_from].tokens -= _value;

                    if (!holderAccounts[_to].alloced)
                        addAccount(_to);

                    uint newHeld = _value + getHeld(holderAccounts[_to].tokens);

                    holderAccounts[_to].tokens = newHeld | (pidFrom * (2 ** 48));
                    allowed[_from][msg.sender] -= _value;
                    Transfer(_from, _to, _value);
                    return true;
                } else { 
                    return false; 
                }
        }


        function balanceOf(address _owner) constant returns (uint256 balance) {
                // vars default to 0
                if (holderAccounts[_owner].alloced) {
                        balance = getHeld(holderAccounts[_owner].tokens);
                } 
        }

        function approve(address _spender, uint256 _value) returns (bool success) {
                allowed[msg.sender][_spender] = _value;
                Approval(msg.sender, _spender, _value);
                return true;
        }

        function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
                return allowed[_owner][_spender];
        }
// ----------------------------------
// END ERC20
// ----------------------------------

  
        // -------------------------------------------
        // check the alloced
        // -------------------------------------------
        function holderExists(address _addr) returns(bool _exist)
        {
                _exist = holderAccounts[_addr].alloced;
        }



        // -------------------------------------------
        // default payable function.
        // if sender is e4row  partner, this is a rake fee payment
        // otherwise this is a token purchase.
        // tokens only purchaseable between tokenfundingstart and end
        // -------------------------------------------
        function () payable {
                if (msg.sender == e4_partner) {
                     feePayment(); // from e4row game escrow contract
                } else {
                     purchaseToken();
                }
        }

        // -----------------------------
        // purchase token function - tokens only sold during sale period up until the max tokens
        // purchase price is tokenPrice.  all units in wei.
        // purchaser will not be included in current pay run
        // -----------------------------
        function purchaseToken() payable {

                uint nvalue = msg.value; // being careful to preserve msg.value
                address npurchaser = msg.sender;
                if (nvalue < tokenPrice) 
                        throw;

                uint qty = nvalue/tokenPrice;
                updateIcoStatus();
                if (icoStatus != IcoStatusValue.saleOpen) // purchase is closed
                        throw;
                if (totalTokensMinted + qty > maxMintableTokens)
                        throw;
                if (!holderAccounts[npurchaser].alloced)
                        addAccount(npurchaser);

                // purchaser waits for next payrun. otherwise can disrupt cur pay run
                uint newHeld = qty + getHeld(holderAccounts[npurchaser].tokens);
                holderAccounts[npurchaser].tokens = newHeld | (curPayoutId * (2 ** 48));

                totalTokensMinted += qty;
                totalTokenFundsReceived += nvalue;

                if (totalTokensMinted == maxMintableTokens) {
                        icoStatus = IcoStatusValue.saleClosed;
                        //test unnecessary -  if (getNumTokensPurchased() >= minIcoTokenGoal)
                        doDeveloperGrant();
                        StatEventI("Purchased,Granted", qty);
                } else
                        StatEventI("Purchased", qty);

        }


        // ---------------------------
        // accept payment from e4row contract
        // ---------------------------
        function feePayment() payable  
        {
                if (msg.sender != e4_partner) {
                        StatEvent("forbidden");
                        return; // thank you
                }
                uint nfvalue = msg.value; // preserve value in case changed in dev grant

                updateIcoStatus();

                holdoverBalance += nfvalue;
                partnerCredits += nfvalue;
                StatEventI("Payment", nfvalue);

                if (holdoverBalance > payoutThreshold
                        || payoutBalance > 0)
                        doPayout();


        }

        // ---------------------------
        // set the e4row partner, this is only done once
        // ---------------------------
        function setE4RowPartner(address _addr) public
        {
        // ONLY owner can set and ONLY ONCE! (unless "unlocked" debug)
        // once its locked. ONLY ONCE!
                if (msg.sender == owner) {
                        if ((e4_partner == address(0)) || (settingsState == SettingStateValue.debug)) {
                                e4_partner = _addr;
                                partnerCredits = 0;
                                //StatEventI("E4-Set", 0);
                        } else {
                                StatEvent("Already Set");
                        }
                }
        }

        // ----------------------------
        // return the total tokens purchased
        // ----------------------------
        function getNumTokensPurchased() constant returns(uint _purchased)
        {
                _purchased = totalTokensMinted-numDevTokens;
        }

        // ----------------------------
        // return the num games as reported from the e4row  contract
        // ----------------------------
        function getNumGames() constant returns(uint _games)
        {
                //_games = 0;
                if (e4_partner != address(0)) {
                        iE4RowEscrow pe4 = iE4RowEscrow(e4_partner);
                        _games = uint(pe4.getNumGamesStarted());
                } 
                //else
                //StatEvent("Empty E4");
        }

        // ------------------------------------------------
        // get the founders, auxPartner, developer
        // --------------------------------------------------
        function getSpecialAddresses() constant returns (address _fndr, address _aux, address _dev, address _e4)
        {
                //if (_sender == owner) { // no msg.sender on constant functions at least in mew
                        _fndr = founderOrg;
                        _aux = auxPartner;
                        _dev = developers;
                        _e4  = e4_partner;
                //}
        }



        // ----------------------------
        // update the ico status
        // ----------------------------
        function updateIcoStatus() public
        {
                if (icoStatus == IcoStatusValue.succeeded 
                        || icoStatus == IcoStatusValue.failed)
                        return;
                else if (icoStatus == IcoStatusValue.anouncement) {
                        if (now > fundingStart && now <= fundingDeadline) {
                                icoStatus = IcoStatusValue.saleOpen;

                        } else if (now > fundingDeadline) {
                                // should not be here - this will eventually fail
                                icoStatus = IcoStatusValue.saleClosed;
                        }
                } else {
                        uint numP = getNumTokensPurchased();
                        uint numG = getNumGames();
                        if ((now > fundingDeadline && numP < minIcoTokenGoal)
                                || (now > usageDeadline && numG < minUsageGoal)) {
                                icoStatus = IcoStatusValue.failed;
                        } else if ((now > fundingDeadline) // dont want to prevent more token sales
                                && (numP >= minIcoTokenGoal)
                                && (numG >= minUsageGoal)) {
                                icoStatus = IcoStatusValue.succeeded; // hooray
                        }
                        if (icoStatus == IcoStatusValue.saleOpen
                                && ((numP >= maxMintableTokens)
                                || (now > fundingDeadline))) {
                                        icoStatus = IcoStatusValue.saleClosed;
                                }
                }

                if (!developersGranted
                        && icoStatus != IcoStatusValue.saleOpen 
                        && icoStatus != IcoStatusValue.anouncement
                        && getNumTokensPurchased() >= minIcoTokenGoal) {
                                doDeveloperGrant(); // grant whenever status goes from open to anything...
                }


        }


        // ----------------------------
        // request refund. Caller must call to request and receive refund 
        // WARNING - withdraw rewards/dividends before calling.
        // YOU HAVE BEEN WARNED
        // ----------------------------
        function requestRefund()
        {
                address nrequester = msg.sender;
                updateIcoStatus();

                uint ntokens = getHeld(holderAccounts[nrequester].tokens);
                if (icoStatus != IcoStatusValue.failed)
                        StatEvent("No Refund");
                else if (ntokens == 0)
                        StatEvent("No Tokens");
                else {
                        uint nrefund = ntokens * tokenPrice;
                        if (getNumTokensPurchased() >= minIcoTokenGoal)
                                nrefund -= (nrefund /10); // only 90 percent b/c 10 percent payout

                        holderAccounts[developers].tokens += ntokens;
                        holderAccounts[nrequester].tokens = 0;
                        if (holderAccounts[nrequester].balance > 0) {
                                // see above warning!!
                                if (!holderAccounts[developers].alloced) 
                                        addAccount(developers);
                                holderAccounts[developers].balance += holderAccounts[nrequester].balance;
                                holderAccounts[nrequester].balance = 0;
                        }

                        if (!nrequester.call.gas(rfGas).value(nrefund)())
                                throw;
                        //StatEventI("Refunded", nrefund);
                }
        }



        // ---------------------------------------------------
        // payout rewards to all token holders
        // use a second holding variable called PayoutBalance to do 
        // the actual payout from b/c too much gas to iterate thru 
        // each payee. Only start a new run at most once per "minpayinterval".
        // Its done in runs of "maxPaysPer"
        // we use special coding for the holderAccounts to avoid a hack
        // of getting paid at the top of the list then transfering tokens
        // to another address at the bottom of the list.
        // because of that each holderAccounts entry gets the payoutid stamped upon it (top two bytes)
        // also a token transfer will transfer the payout id.
        // ---------------------------------------------------
        function doPayout()  internal
        {
                if (totalTokensMinted == 0)
                        return;

                if ((holdoverBalance > 0) 
                        && (payoutBalance == 0)
                        && (now > (lastPayoutTime+minPayInterval))) {
                        // start a new run
                        curPayoutId++;
                        if (curPayoutId >= 32768)
                                curPayoutId = 1;
                        lastPayoutTime = now;
                        payoutBalance = int(holdoverBalance);
                        prOrigPayoutBal = payoutBalance;
                        prOrigTokensMint = totalTokensMinted;
                        holdoverBalance = 0;
                        lastPayoutIndex = 0;
                        StatEventI("StartRun", uint(curPayoutId));
                } else if (payoutBalance > 0) {
                        // work down the p.o.b
                        uint nAmount;
                        uint nPerTokDistrib = uint(prOrigPayoutBal)/prOrigTokensMint;
                        uint paids = 0;
                        uint i; // intentional
                        for (i = lastPayoutIndex; (paids < maxPaysPer) && (i < numAccounts) && (payoutBalance > 0); i++ ) {
                                address a = holderIndexes[i];
                                if (a == address(0)) {
                                        continue;
                                }
                                var (pid, held) = getPayIdAndHeld(holderAccounts[a].tokens);
                                if ((held > 0) && (pid != curPayoutId)) {
                                        nAmount = nPerTokDistrib * held;
                                        if (int(nAmount) <= payoutBalance){
                                                holderAccounts[a].balance += nAmount; 
                                                holderAccounts[a].tokens = (curPayoutId * (2 ** 48)) | held;
                                                payoutBalance -= int(nAmount);
                                                paids++;
                                        }
                                }
                        }
                        lastPayoutIndex = i;
                        if (lastPayoutIndex >= numAccounts || payoutBalance <= 0) {
                                lastPayoutIndex = 0;
                                if (payoutBalance > 0)
                                        holdoverBalance += uint(payoutBalance);// put back any leftovers
                                payoutBalance = 0;
                                StatEventI("RunComplete", uint(prOrigPayoutBal) );

                        } else {
                                StatEventI("PayRun", nPerTokDistrib );
                        }
                }

        }


        // ----------------------------
        // sender withdraw entire rewards/dividends
        // ----------------------------
        function withdrawDividends() public returns (uint _amount)
        {
                if (holderAccounts[msg.sender].balance == 0) { 
                        //_amount = 0;
                        StatEvent("0 Balance");
                        return;
                } else {
                        if ((msg.sender == developers) 
                                &&  (now < vestTime)) {
                                //statEvent("Tokens not yet vested.");
                                //_amount = 0;
                                return;
                        }

                        _amount = holderAccounts[msg.sender].balance; 
                        holderAccounts[msg.sender].balance = 0; 
                        if (!msg.sender.call.gas(rwGas).value(_amount)())
                                throw;
                        //StatEventI("Paid", _amount);

                }

        }

        // ----------------------------
        // set gas for operations
        // ----------------------------
        function setOpGas(uint _rm, uint _rf, uint _rw)
        {
                if (msg.sender != owner && msg.sender != developers) {
                        //StatEvent("only owner calls");
                        return;
                } else {
                        rmGas = _rm;
                        rfGas = _rf;
                        rwGas = _rw;
                }
        }

        // ----------------------------
        // get gas for operations
        // ----------------------------
        function getOpGas() constant returns (uint _rm, uint _rf, uint _rw)
        {
                _rm = rmGas;
                _rf = rfGas;
                _rw = rwGas;
        }
 

        // ----------------------------
        // check rewards.  pass in address of token holder
        // ----------------------------
        function checkDividends(address _addr) constant returns(uint _amount)
        {
                if (holderAccounts[_addr].alloced)
                        _amount = holderAccounts[_addr].balance;
        }


        // ------------------------------------------------
        // icoCheckup - check up call for administrators
        // after sale is closed if min ico tokens sold, 10 percent will be distributed to 
        // company to cover various operating expenses
        // after sale and usage dealines have been met, remaining 90 percent will be distributed to
        // company.
        // ------------------------------------------------
        function icoCheckup() public
        {
                if (msg.sender != owner && msg.sender != developers)
                        throw;

                uint nmsgmask;
                //nmsgmask = 0;

                if (icoStatus == IcoStatusValue.saleClosed) {
                        if ((getNumTokensPurchased() >= minIcoTokenGoal)
                                && (remunerationStage == 0 )) {
                                remunerationStage = 1;
                                remunerationBalance = (totalTokenFundsReceived/100)*9; // 9 percent
                                auxPartnerBalance =  (totalTokenFundsReceived/100); // 1 percent
                                nmsgmask |= 1;
                        } 
                }
                if (icoStatus == IcoStatusValue.succeeded) {

                        if (remunerationStage == 0 ) {
                                remunerationStage = 1;
                                remunerationBalance = (totalTokenFundsReceived/100)*9; 
                                auxPartnerBalance =  (totalTokenFundsReceived/100);
                                nmsgmask |= 4;
                        }
                        if (remunerationStage == 1) { // we have already suceeded
                                remunerationStage = 2;
                                remunerationBalance += totalTokenFundsReceived - (totalTokenFundsReceived/10); // 90 percent
                                nmsgmask |= 8;
                        }

                }

                uint ntmp;

                if (remunerationBalance > 0) { 
                // only pay one entity per call, dont want to run out of gas
                                ntmp = remunerationBalance;
                                remunerationBalance = 0;
                                if (!founderOrg.call.gas(rmGas).value(ntmp)()) {
                                        remunerationBalance = ntmp;
                                        nmsgmask |= 32;
                                } else {
                                        nmsgmask |= 64;
                                }
                } else  if (auxPartnerBalance > 0) {
                // note the "else" only pay one entity per call, dont want to run out of gas
                        ntmp = auxPartnerBalance;
                        auxPartnerBalance = 0;
                        if (!auxPartner.call.gas(rmGas).value(ntmp)()) {
                                auxPartnerBalance = ntmp;
                                nmsgmask |= 128;
                        }  else {
                                nmsgmask |= 256;
                        }

                } 

                StatEventI("ico-checkup", nmsgmask);
        }


        // ----------------------------
        // swap executor
        // ----------------------------
        function changeOwner(address _addr) 
        {
                if (msg.sender != owner
                        || settingsState == SettingStateValue.lockedRelease)
                         throw;

                owner = _addr;
        }

        // ----------------------------
        // swap developers account
        // ----------------------------
        function changeDevevoperAccont(address _addr) 
        {
                if (msg.sender != owner
                        || settingsState == SettingStateValue.lockedRelease)
                         throw;
                developers = _addr;
        }

        // ----------------------------
        // change founder
        // ----------------------------
        function changeFounder(address _addr) 
        {
                if (msg.sender != owner
                        || settingsState == SettingStateValue.lockedRelease)
                         throw;
                founderOrg = _addr;
        }

        // ----------------------------
        // change auxPartner
        // ----------------------------
        function changeAuxPartner(address _aux) 
        {
                if (msg.sender != owner
                        || settingsState == SettingStateValue.lockedRelease)
                         throw;
                auxPartner = _aux;
        }


        // ----------------------------
        // DEBUG ONLY - end this contract, suicide to developers
        // ----------------------------
        function haraKiri()
        {
                if (settingsState != SettingStateValue.debug)
                        throw;
                if (msg.sender != owner)
                         throw;
                suicide(developers);
        }

        // ----------------------------
        // get all ico status, funding and usage info
        // ----------------------------
        function getIcoInfo() constant returns(IcoStatusValue _status, uint _saleStart, uint _saleEnd, uint _usageEnd, uint _saleGoal, uint _usageGoal, uint _sold, uint _used, uint _funds, uint _credits, uint _remuStage, uint _vest)
        {
                _status = icoStatus;
                _saleStart = fundingStart;
                _saleEnd = fundingDeadline;
                _usageEnd = usageDeadline;
                _vest = vestTime;
                _saleGoal = minIcoTokenGoal;
                _usageGoal = minUsageGoal;
                _sold = getNumTokensPurchased();
                _used = getNumGames();
                _funds = totalTokenFundsReceived;
                _credits = partnerCredits;
                _remuStage = remunerationStage;
        }

        function flushDividends()
        {
                if ((msg.sender != owner) && (msg.sender != developers))
                        return;
                if (holdoverBalance > 0 || payoutBalance > 0)
                        doPayout();
        }

        function doDeveloperGrant() internal
        {
                if (!developersGranted) {
                        developersGranted = true;
                        numDevTokens = totalTokensMinted/10;
                        totalTokensMinted += numDevTokens;
                        if (!holderAccounts[developers].alloced) 
                                addAccount(developers);
                        uint newHeld = getHeld(holderAccounts[developers].tokens) + numDevTokens;
                        holderAccounts[developers].tokens = newHeld |  (curPayoutId * (2 ** 48));

                }
        }


}