contract AmberToken is Token, Owned {
  struct Account {
    // Balance is always less than or equal totalSupply since totalSupply is increased straight away of when releasing locked tokens.
    uint balance;
    mapping (address => uint) allowanceOf;

    // TokensPerPhase is always less than or equal to totalSupply since anything added to it is UNLOCK_PHASES times lower than added to totalSupply.
    uint tokensPerPhase;
    uint nextPhase;
  }

  event Minted(address indexed who, uint value);
  event MintedLocked(address indexed who, uint value);

  function AmberToken() {}

  // Mint a certain number of tokens.
  // _value has to be bounded not to overflow.
  function mint(address _who, uint _value)
    only_owner
    public
  {
    accounts[_who].balance += _value;
    totalSupply += _value;
    Minted(_who, _value);
  }

  // Mint a certain number of tokens that are locked up.
  // _value has to be bounded not to overflow.
  function mintLocked(address _who, uint _value)
    only_owner
    public
  {
    accounts[_who].tokensPerPhase += _value / UNLOCK_PHASES;
    totalSupply += _value;
    MintedLocked(_who, _value);
  }

  /// Finalise any minting operations. Resets the owner and causes normal tokens
  /// to be liquid. Also begins the countdown for locked-up tokens.
  function finalise()
    only_owner
    public
  {
    locked = false;
    owner = 0;
    phaseStart = now;
  }

  /// Return the current unlock-phase. Won't work until after the contract
  /// has `finalise()` called.
  function currentPhase()
    public
    constant
    returns (uint)
  {
    require (phaseStart > 0);
    uint p = (now - phaseStart) / PHASE_DURATION;
    return p > UNLOCK_PHASES ? UNLOCK_PHASES : p;
  }

  /// Unlock any now freeable tokens that are locked up for account `_who`.
  function unlockTokens(address _who)
    public
  {
    uint phase = currentPhase();
    uint tokens = accounts[_who].tokensPerPhase;
    uint nextPhase = accounts[_who].nextPhase;
    if (tokens > 0 && phase > nextPhase) {
      accounts[_who].balance += tokens * (phase - nextPhase);
      accounts[_who].nextPhase = phase;
    }
  }

  // Transfer tokens between accounts.
  function transfer(address _to, uint256 _value)
    when_owns(msg.sender, _value)
    when_liquid
    returns (bool)
  {
    Transfer(msg.sender, _to, _value);
    accounts[msg.sender].balance -= _value;
    accounts[_to].balance += _value;

    return true;
  }

  // Transfer via allowance.
  function transferFrom(address _from, address _to, uint256 _value)
    when_owns(_from, _value)
    when_has_allowance(_from, msg.sender, _value)
    when_liquid
    returns (bool)
  {
    Transfer(_from, _to, _value);
    accounts[_from].allowanceOf[msg.sender] -= _value;
    accounts[_from].balance -= _value;
    accounts[_to].balance += _value;

    return true;
  }

  // Approve allowances
  function approve(address _spender, uint256 _value)
    when_liquid
    returns (bool)
  {
    // Mitigate the race condition described here:
    // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    require (_value == 0 || accounts[msg.sender].allowanceOf[_spender] == 0);
    Approval(msg.sender, _spender, _value);
    accounts[msg.sender].allowanceOf[_spender] = _value;

    return true;
  }

  // Get the balance of a specific address.
  function balanceOf(address _who) constant returns (uint256) {
    return accounts[_who].balance;
  }

  // Available allowance
  function allowance(address _owner, address _spender)
    constant
    returns (uint256)
  {
    return accounts[_owner].allowanceOf[_spender];
  }

  // The balance should be available
  modifier when_owns(address _owner, uint _amount) {
    require (accounts[_owner].balance >= _amount);
    _;
  }

  // An allowance should be available
  modifier when_has_allowance(address _owner, address _spender, uint _amount) {
    require (accounts[_owner].allowanceOf[_spender] >= _amount);
    _;
  }

  // Tokens must not be locked.
  modifier when_liquid {
    require (!locked);
    _;
  }

  /// Usual token descriptors.
  string constant public name = "Amber Token";
  uint8 constant public decimals = 18;
  string constant public symbol = "AMB";

  // Are the tokens non-transferrable?
  bool public locked = true;

  // Phase information for slow-release tokens.
  uint public phaseStart = 0;
  uint public constant PHASE_DURATION = 180 days;
  uint public constant UNLOCK_PHASES = 4;

  // available token supply
  uint public totalSupply;

  // storage and mapping of all balances & allowances
  mapping (address => Account) accounts;
}
// BasicCoin, ECR20 tokens that all belong to the owner for sending around
function finalise()
  only_owner
  public
{
  locked = false;
  owner = 0;
  phaseStart = now;
}

/// Finalise any minting operations. Resets the owner and causes normal tokens
/// to be liquid. Also begins the countdown for locked-up tokens.