contract PATH is MintableToken, BurnableToken, SafePayloadChecker {
  /**
   * @dev the original supply, for posterity, since totalSupply will decrement on burn
   */
  uint256 public initialSupply = 400000000 * (10 ** uint256(decimals));

  /**
   * ERC20 Identification Functions
   */
  string public constant name    = "PATH Token"; // solium-disable-line uppercase
  string public constant symbol  = "PATH"; // solium-disable-line uppercase
  uint8 public constant decimals = 18; // solium-disable-line uppercase

  /**
   * @dev the time at which token holders can begin transferring tokens
   */
  uint256 public transferableStartTime;

  address privatePresaleWallet;
  address publicPresaleContract;
  address publicCrowdsaleContract;
  address pathTeamMultisig;
  TokenVesting public founderTokenVesting;

  /**
   * @dev the token sale contract(s) and team can move tokens
   * @dev   before the lockup expires
   */
  modifier onlyWhenTransferEnabled()
  {
    if (now <= transferableStartTime) {
      require(
        msg.sender == privatePresaleWallet || // solium-disable-line operator-whitespace
        msg.sender == publicPresaleContract || // solium-disable-line operator-whitespace
        msg.sender == publicCrowdsaleContract || // solium-disable-line operator-whitespace
        msg.sender == pathTeamMultisig
      );
    }
    _;
  }

  /**
   * @dev require that this contract cannot affect itself
   */
  modifier validDestination(address _addr)
  {
    require(_addr != address(this));
    _;
  }

  /**
   * @dev Constructor
   */
  function PATH(uint256 _transferableStartTime)
    public
  {
    transferableStartTime = _transferableStartTime;
  }

  /**
   * @dev override transfer token for a specified address to add validDestination
   * @param _to The address to transfer to.
   * @param _value The amount to be transferred.
   */
  function transfer(address _to, uint256 _value)
    onlyPayloadSize(32 + 32) // address (32) + uint256 (32)
    validDestination(_to)
    onlyWhenTransferEnabled
    public
    returns (bool)
  {
    return super.transfer(_to, _value);
  }

  /**
   * @dev override transferFrom token for a specified address to add validDestination
   * @param _from The address to transfer from.
   * @param _to The address to transfer to.
   * @param _value The amount to be transferred.
   */
  function transferFrom(address _from, address _to, uint256 _value)
    onlyPayloadSize(32 + 32 + 32) // address (32) + address (32) + uint256 (32)
    validDestination(_to)
    onlyWhenTransferEnabled
    public
    returns (bool)
  {
    return super.transferFrom(_from, _to, _value);
  }

  /**
   * @dev burn tokens, but also include a Transfer(sender, 0x0, value) event
   * @param _value The amount to be burned.
   */
  function burn(uint256 _value)
    onlyWhenTransferEnabled
    public
  {
    super.burn(_value);
  }

  /**
   * @dev burn tokens on behalf of someone
   * @param _from The address of the owner of the token.
   * @param _value The amount to be burned.
   */
  function burnFrom(address _from, uint256 _value)
    onlyPayloadSize(32 + 32) // address (32) + uint256 (32)
    onlyWhenTransferEnabled
    public
  {
    // require(_value <= allowed[_from][msg.sender]);
    require(_value <= balances[_from]);

    balances[_from] = balances[_from].sub(_value);
    totalSupply_ = totalSupply_.sub(_value);
    Burn(_from, _value);
    Transfer(_from, address(0), _value);
  }

  /**
   * @dev override approval functions to include safe payload checking
   */
  function approve(address _spender, uint256 _value)
    onlyPayloadSize(32 + 32) // address (32) + uint256 (32)
    public
    returns (bool)
  {
    return super.approve(_spender, _value);
  }

  function increaseApproval(address _spender, uint256 _addedValue)
    onlyPayloadSize(32 + 32) // address (32) + uint256 (32)
    public
    returns (bool)
  {
    return super.increaseApproval(_spender, _addedValue);
  }

  function decreaseApproval(address _spender, uint256 _subtractedValue)
    onlyPayloadSize(32 + 32) // address (32) + uint256 (32)
    public
    returns (bool)
  {
    return super.decreaseApproval(_spender, _subtractedValue);
  }


  /**
   * @dev distribute the tokens once the crowdsale addresses are known
   * @dev only callable once and disables minting at the end
   */
  function distributeTokens(
    address _privatePresaleWallet,
    address _publicPresaleContract,
    address _publicCrowdsaleContract,
    address _pathCompanyMultisig,
    address _pathAdvisorVault,
    address _pathFounderAddress
  )
    onlyOwner
    canMint
    external
  {
    // Set addresses
    privatePresaleWallet = _privatePresaleWallet;
    publicPresaleContract = _publicPresaleContract;
    publicCrowdsaleContract = _publicCrowdsaleContract;
    pathTeamMultisig = _pathCompanyMultisig;

    // Mint all tokens according to the established allocations
    mint(_privatePresaleWallet, 200000000 * (10 ** uint256(decimals)));
    // ^ 50%
    mint(_publicPresaleContract, 32000000 * (10 ** uint256(decimals)));
    // ^ 8%
    mint(_publicCrowdsaleContract, 8000000 * (10 ** uint256(decimals)));
    // ^ 2%
    mint(_pathCompanyMultisig, 80000000 * (10 ** uint256(decimals)));
    // ^ 20%
    mint(_pathAdvisorVault, 40000000 * (10 ** uint256(decimals)));
    // ^ 10%

    // deploy a token vesting contract for the founder tokens
    uint256 cliff = 6 * 4 weeks; // 4 months
    founderTokenVesting = new TokenVesting(
      _pathFounderAddress,
      now,   // start vesting now
      cliff, // cliff time
      cliff, // 100% unlocked at cliff
      false  // irrevocable
    );
    // and then mint tokens to the vesting contract
    mint(address(founderTokenVesting), 40000000 * (10 ** uint256(decimals)));
    // ^ 10%

    // immediately finish minting
    finishMinting();

    assert(totalSupply_ == initialSupply);
  }
}
function PATH(uint256 _transferableStartTime)
  public
{
  transferableStartTime = _transferableStartTime;
}

/**
 * @dev Constructor
 */