contract FidentiaXTokenSale is Ownable,Sender {

  using SafeMath for uint256;

  // The token being sold
  FidentiaXToken public token;

  uint256 public decimals;  

  uint256 public oneCoin;

  // start and end block where investments are allowed (both inclusive)
  uint256 public startTimestamp;
  uint256 public endTimestamp;

  // timestamps for tiers
  uint256 public tier1Timestamp;
  uint256 public tier2Timestamp;

  // address where funds are collected

  address public multiSig;

  function setWallet(address _newWallet) public onlyOwner {
    multiSig = _newWallet;
  }

  // These will be set by setTier()

  uint256 public rate; // how many token units a buyer gets per wei

  uint256 public minContribution = 0.0001 ether;  // minimum contributio to participate in tokensale

  uint256 public maxContribution = 200000 ether;  // default limit to tokens that the users can buy

  // ***************************
  // amount of raised money in wei

  uint256 public weiRaised;

  // amount of raised tokens 

  uint256 public tokenRaised;

  // maximum amount of tokens being created

  uint256 public maxTokens;

  // maximum amount of tokens for sale

  uint256 public tokensForSale;  // 24 Million Tokens for SALE

  // number of participants in presale

  uint256 public numberOfPurchasers = 0;

  //  for whitelist
  address public cs;
  //  for whitelist AND placement
  address public fx;

  // switch on/off the authorisation , default: true - on

  bool    public freeForAll = false;

  mapping (address => bool) public authorised; // just to annoy the heck out of americans

  event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

  event SaleClosed();

  function FidentiaXTokenSale() public {
    startTimestamp = 1509930000; //  Monday November 06, 2017 09:00:00 (am) in time zone Asia/Singapore (SGT)
    //1508684400;
    endTimestamp = 1512489599;   //  December 05, 2017 23:59:59 (pm) in time zone Asia/Singapore (SGT) ( GMT +08:00 )
    tier1Timestamp = 1510102799; //   November 08, 2017 08:59:59 (am) in time zone Asia/Singapore (SGT)
    tier2Timestamp = 1510361999; //   November 11, 2017 08:59:59 (am) in time zone Asia/Singapore (SGT)
    multiSig = 0x90420B8aef42F856a0AFB4FFBfaA57405FB190f3;
    token = new FidentiaXToken();
    decimals = token.decimals();
    oneCoin = 10 ** decimals;
    maxTokens = 130 * (10**6) * oneCoin;
    tokensForSale = 130 * (10**6) * oneCoin;
  }

  /**
  * @dev Calculates the amount of bonus coins the buyer gets
   */
  function getRateAt(uint256 at) internal constant returns (uint256) {
    if (at < (tier1Timestamp))
      return 575;
    if (at < (tier2Timestamp))
      return 550;
    return 500;
  }

  // @return true if crowdsale event has ended
  function hasEnded() public constant returns (bool) {
    if (now > endTimestamp)
      return true;
    if (tokenRaised >= tokensForSale)
      return true; // if we reach the tokensForSale
    return false;
 }
  /**
  * @dev throws if person sending is not contract owner or cs role
   */
  modifier onlyCSorFx() {
    require((msg.sender == fx) || (msg.sender==cs));
    _;
  }

  modifier onlyFx() {
    require(msg.sender == fx);
    _;
  }

  /**
  * @dev throws if person sending is not authorised or sends nothing
  */
  modifier onlyAuthorised() {
    require (authorised[msg.sender] || freeForAll);
    require (now >= startTimestamp);
    require (!(hasEnded()));
    require (multiSig != 0x0);
    require (msg.value > 1 finney);
    require(tokensForSale > tokenRaised); // check we are not over the number of tokensForSale
    _;
  }

  /**
  * @dev authorise an account to participate
  */
  function authoriseAccount(address whom) onlyCSorFx public {
    authorised[whom] = true;
  }

  /**
  * @dev authorise a lot of accounts in one go
  */
  function authoriseManyAccounts(address[] many) onlyCSorFx public {
    for (uint256 i = 0; i < many.length; i++) {
      authorised[many[i]] = true;
    }
  }

  /**
  * @dev ban an account from participation (default)
  */
  function blockAccount(address whom) onlyCSorFx public {
    authorised[whom] = false;
  }

  /**
  * @dev set a new CS representative
  */
  function setCS(address newCS) onlyOwner public {
    cs = newCS;
  }

  /**
  * @dev set a new Fx representative
  */
  function setFx(address newFx) onlyOwner public {
    fx = newFx;
  }

  function placeTokens(address beneficiary, uint256 _tokens) onlyFx public {
    //check minimum and maximum amount
    require(_tokens != 0);
    require(!hasEnded());
    uint256 amount = 0;
    if (token.balanceOf(beneficiary) == 0) {
      numberOfPurchasers++;
    }
    tokenRaised = tokenRaised.add(_tokens); // so we can go slightly over
    token.mint(beneficiary, _tokens);
    TokenPurchase(beneficiary, beneficiary, amount, _tokens);
  }

  // low level token purchase function
  function buyTokens(address beneficiary, uint256 amount) onlyAuthorised internal {
    //check minimum and maximum amount
    require(amount >= minContribution);
    require(amount <= maxContribution);

    // Calculate token amount to be purchased
    uint256 actualRate = getRateAt(now);
    uint256 tokens = amount.mul(actualRate);

    // update state
    weiRaised = weiRaised.add(amount);
    if (token.balanceOf(beneficiary) == 0) {
      numberOfPurchasers++;
    }
    tokenRaised = tokenRaised.add(tokens); // so we can go slightly over
    token.mint(beneficiary, tokens);
    TokenPurchase(beneficiary, beneficiary, amount, tokens);
    SendThreeWays(multiSig,this.balance); // better in case any other ether ends up here
  }

  // transfer ownership of the token to the owner of the presale contract
  function finishSale() public onlyOwner {
    require(hasEnded());
    // assign the rest of the 100M tokens to the reserve
    uint unassigned;
    if(maxTokens > tokenRaised) {
      unassigned  = maxTokens.sub(tokenRaised);
      token.mint(multiSig,unassigned);
    }
    token.finishMinting();
    token.transferOwnership(owner);
    SaleClosed();
  }

  // fallback function can be used to buy tokens
  function () public payable {
    buyTokens(msg.sender, msg.value);
  }

  function emergencyERC20Drain( ERC20 oddToken, uint amount ) public {
    oddToken.transfer(owner, amount);
  }
}
function setFx(address newFx) onlyOwner public {
  fx = newFx;
}

/**
 * @dev set a new Fx representative
 */