contract GenesisCryptoTechnology is Token {

	/// TOKEN META DATA
	string constant public name = 'GenesisCryptoTechnology';
	string constant public symbol = 'GCT';
	uint8  constant public decimals = 8;
 uint256 public exchangeRate = 5880; 

	/// ALOCATIONS
	// To calculate vesting periods we assume that 1 month is always equal to 30 days 


	/*** Initial Investors' tokens ***/

	// 600,000,00 (60%) tokens are distributed among initial investors
	// These tokens will be distributed without vesting

	address public investorsAllocation = address(0x11195539543Ec8E6fe7179112E42fe1d3c434Ed4);
	uint256 public investorsTotal = 60000000e8;


	/*** Overdraft Reserves ***/

	// 200,000,00 (20%) tokens will be eventually available for overdraft
	// These tokens will be distributed monthly with a 6 month cliff within a year
	// 41,666,666 tokens will be unlocked every month after the cliff
	// 4 tokens will be unlocked without vesting to ensure that total amount sums up to 250,000,000.

	address public overdraftAllocation = address(0xa218A1Ae3D584d02598C3c5Aa675E547bBeeE0E7);
	uint256 public overdraftTotal = 20000000e8;
	uint256 public overdraftPeriodAmount = 41666666e8;
	uint256 public overdraftUnvested = 4e8;
	uint256 public overdraftCliff = 5 * 30 days;
	uint256 public overdraftPeriodLength = 810 days;
	uint8   public overdraftPeriodsNumber = 6;


	/*** Tokens reserved for Founders and Team ***/

	// 150,000,00 (15%) tokens will be eventually available for the team
	// These tokens will be distributed every 3 month without a cliff within 4 years
	// 7,031,250 tokens will be unlocked every 3 month

	address public teamAllocation  = address(0x4ee4562cc0eeC0381a974efffe768ce2017632Ad);
	uint256 public teamTotal = 15000000e8;
	uint256 public teamPeriodAmount = 7031250e8;
	uint256 public teamUnvested = 0;
	uint256 public teamCliff = 0;
	uint256 public teamPeriodLength = 3 * 810 days;
	uint8   public teamPeriodsNumber = 16;



	/*** Tokens reserved for Community Building and Airdrop Campaigns ***/

	// 40,000,00 (4%) tokens will be eventually available for the community
	// 10,000,002 tokens will be available instantly without vesting
	// 49,999,998 tokens will be distributed every 3 month without a cliff within 18 months
	// 8,333,333 tokens will be unlocked every 3 month


	address public communityAllocation  = address(0x99559c417313e61aE699FD55B9A2FD533e97dAB1);
	uint256 public communityTotal = 4000000e8;
	uint256 public communityPeriodAmount = 8333333e8;
	uint256 public communityUnvested = 10000002e8;
	uint256 public communityCliff = 0;
	uint256 public communityPeriodLength = 3 * 810 days;
	uint8   public communityPeriodsNumber = 6;



	/*** Tokens reserved for Advisors, Legal and PR ***/

	// 10,000,00 (1%) tokens will be eventually available for advisers
	// 25,000,008 tokens will be available instantly without vesting
	// 27 499 992 tokens will be distributed monthly without a cliff within 12 months
	// 2,291,666 tokens will be unlocked every month

	address public advisersAllocation  = address(0x3E553bB7c931DC752E9CDd7Acb52e6F0b2bEB35E);
	uint256 public advisersTotal = 1000000e8;
	uint256 public advisersPeriodAmount = 2291666e8;
	uint256 public advisersUnvested = 25000008e8;
	uint256 public advisersCliff = 0;
	uint256 public advisersPeriodLength = 1 days;
	uint8   public advisersPeriodsNumber = 12;


	/// CONSTRUCTOR

	function GenesisCryptoTechnology() public {
		//  Overall, 1,000,000,00 tokens exist
		totalSupply = 100000000e8;

		balances[investorsAllocation] = investorsTotal;
		balances[overdraftAllocation] = overdraftTotal;
		balances[teamAllocation] = teamTotal;
		balances[communityAllocation] = communityTotal;
		balances[advisersAllocation] = advisersTotal;

		// Unlock some tokens without vesting
		allowed[investorsAllocation][msg.sender] = investorsTotal;
		allowed[overdraftAllocation][msg.sender] = overdraftUnvested;
		allowed[communityAllocation][msg.sender] = communityUnvested;
		allowed[advisersAllocation][msg.sender] = advisersUnvested;
	}

	/// DISTRIBUTION

	function distributeInvestorsTokens(address _to, uint256 _amountWithDecimals)
		public
		onlyOwner
	{
		require(transferFrom(investorsAllocation, _to, _amountWithDecimals));
	}

	/// VESTING

	function withdrawOverdraftTokens(address _to, uint256 _amountWithDecimals)
		public
		onlyOwner
	{
		allowed[overdraftAllocation][msg.sender] = allowance(overdraftAllocation, msg.sender);
		require(transferFrom(overdraftAllocation, _to, _amountWithDecimals));
	}

	function withdrawTeamTokens(address _to, uint256 _amountWithDecimals)
		public
		onlyOwner 
	{
		allowed[teamAllocation][msg.sender] = allowance(teamAllocation, msg.sender);
		require(transferFrom(teamAllocation, _to, _amountWithDecimals));
	}

	function withdrawCommunityTokens(address _to, uint256 _amountWithDecimals)
		public
		onlyOwner 
	{
		allowed[communityAllocation][msg.sender] = allowance(communityAllocation, msg.sender);
		require(transferFrom(communityAllocation, _to, _amountWithDecimals));
	}

	function withdrawAdvisersTokens(address _to, uint256 _amountWithDecimals)
		public
		onlyOwner 
	{
		allowed[advisersAllocation][msg.sender] = allowance(advisersAllocation, msg.sender);
		require(transferFrom(advisersAllocation, _to, _amountWithDecimals));
	}

	/// @dev Overrides StandardToken.sol function
	function allowance(address _owner, address _spender)
		public
		view
		returns (uint256 remaining)
	{   
		if (_spender != owner) {
			return allowed[_owner][_spender];
		}

		uint256 unlockedTokens;
		uint256 spentTokens;

		if (_owner == overdraftAllocation) {
			unlockedTokens = _calculateUnlockedTokens(
				overdraftCliff,
				overdraftPeriodLength,
				overdraftPeriodAmount,
				overdraftPeriodsNumber,
				overdraftUnvested
			);
			spentTokens = sub(overdraftTotal, balanceOf(overdraftAllocation));
		} else if (_owner == teamAllocation) {
			unlockedTokens = _calculateUnlockedTokens(
				teamCliff,
				teamPeriodLength,
				teamPeriodAmount,
				teamPeriodsNumber,
				teamUnvested
			);
			spentTokens = sub(teamTotal, balanceOf(teamAllocation));
		} else if (_owner == communityAllocation) {
			unlockedTokens = _calculateUnlockedTokens(
				communityCliff,
				communityPeriodLength,
				communityPeriodAmount,
				communityPeriodsNumber,
				communityUnvested
			);
			spentTokens = sub(communityTotal, balanceOf(communityAllocation));
		} else if (_owner == advisersAllocation) {
			unlockedTokens = _calculateUnlockedTokens(
				advisersCliff,
				advisersPeriodLength,
				advisersPeriodAmount,
				advisersPeriodsNumber,
				advisersUnvested
			);
			spentTokens = sub(advisersTotal, balanceOf(advisersAllocation));
		} else {
			return allowed[_owner][_spender];
		}

		return sub(unlockedTokens, spentTokens);
	}

	/// @dev Overrides Owned.sol function
	function confirmOwnership()
		public
		onlyPotentialOwner
	{   
		// Forbid the old owner to distribute investors' tokens
		allowed[investorsAllocation][owner] = 0;

		// Allow the new owner to distribute investors' tokens
		allowed[investorsAllocation][msg.sender] = balanceOf(investorsAllocation);

		// Forbid the old owner to withdraw any tokens from the reserves
		allowed[overdraftAllocation][owner] = 0;
		allowed[teamAllocation][owner] = 0;
		allowed[communityAllocation][owner] = 0;
		allowed[advisersAllocation][owner] = 0;

		super.confirmOwnership();
	}

	function _calculateUnlockedTokens(
		uint256 _cliff,
		uint256 _periodLength,
		uint256 _periodAmount,
		uint8 _periodsNumber,
		uint256 _unvestedAmount
	)
		private
		view
		returns (uint256) 
	{
		/* solium-disable-next-line security/no-block-members */
		if (now < add(creationTime, _cliff)) {
			return _unvestedAmount;
		}
		/* solium-disable-next-line security/no-block-members */
		uint256 periods = div(sub(now, add(creationTime, _cliff)), _periodLength);
		periods = periods > _periodsNumber ? _periodsNumber : periods;
		return add(_unvestedAmount, mul(periods, _periodAmount));
	}
}
/// @author Zerion - <inbox@zerion.io>
function confirmOwnership()
	public
	onlyPotentialOwner
{   
	// Forbid the old owner to distribute investors' tokens
	allowed[investorsAllocation][owner] = 0;

	// Allow the new owner to distribute investors' tokens
	allowed[investorsAllocation][msg.sender] = balanceOf(investorsAllocation);

	// Forbid the old owner to withdraw any tokens from the reserves
	allowed[overdraftAllocation][owner] = 0;
	allowed[teamAllocation][owner] = 0;
	allowed[communityAllocation][owner] = 0;
	allowed[advisersAllocation][owner] = 0;

	super.confirmOwnership();
}

/// @dev Overrides Owned.sol function