contract SwissCryptoExchangeCompany is BaseCompany {
  event ProcessedInvestment(address indexed investor, uint256 weiAmount, uint256 shares);
  event SaleCompleted(address indexed beneficiary, uint256 weiAmount, uint256 shares);
  event SaleEnded(uint256 endedAt);
  event SaleAborted(uint256 abortedAt);

  using SafeMath for uint256;

  Sale public currentSale;

  // Definition of a sale.
  struct Sale {
    address creator;
    address beneficiary;
    address investor;
    address shareholder;
    uint256 rate;
    uint256 weiRaised;
    uint256 sharesSold;
    uint256 sharesCap;
    bool ended;
    bool exists;
  }
  
  /**
   * @dev Create a new instance of the company contract.
   * @param _manager address
   */
  function SwissCryptoExchangeCompany(address _manager) public BaseCompany("SwissCryptoExchangeCompany", "1.0.1", 101, _manager) {}

  /**
   * @dev Ensure the msg.sender is an shareholder of the company.
   */
  modifier onlyShareholder() {
    require(isShareholder(msg.sender));
    _; 
  }
  
  /**
   * @dev Ensure the msg.sender is has over 50% of the company shares.
   */
  modifier onlyMajority() {
    require(isMajorityShareholder(msg.sender));
    _;
  }

  /**
   * @dev Ensure the msg.sender is thesale creator.
   */
  modifier onlySaleCreator() {
    require(msg.sender == currentSale.creator);
    _; 
  }
  
  /**
   * @dev Ensure there is no sale in progress.
   */
  modifier onlyWhenNotSelling() { 
    require(!currentSale.exists);
    _; 
  }
  
  /**
   * @dev Ensure there is a sale in progress.
   */
  modifier onlyWhenSelling() { 
    require(currentSale.exists);
    _; 
  }

  
  /**
   * @dev Handle an incoming ether transfer.
   */
  function ()
    public
    payable
    isActive
    onlyWhenSelling
  {
    // Validate the purchase.
    require(msg.sender == currentSale.investor && msg.value > 0);

    // Forward the call to the Sale contract.
    processPayment();
  }

  /**
   * @dev Initialize a new sale.
   * @param rate         uint256
   * @param sharesCap    uint256
   * @param beneficiary  address 
   * @param investor     address 
   */
  function initializeNewSale(
    uint256 rate,
    uint256 sharesCap,
    address beneficiary,
    address investor
  )
    public
    isActive
    onlyMajority
    onlyWhenNotSelling
  {
    // Validate the parameters.
    require(rate > 0);
    require(sharesCap > 0);
    require(beneficiary != 0x0);
    require(investor != 0x0);
    require(token().balanceOf(msg.sender) >= sharesCap);

    // Set sale properties.
    currentSale.creator = msg.sender;
    currentSale.rate = rate;
    currentSale.sharesCap = sharesCap;
    currentSale.beneficiary = beneficiary;
    currentSale.investor = investor;
    currentSale.shareholder = msg.sender;
    currentSale.weiRaised = 0;
    currentSale.sharesSold = 0;
    currentSale.ended = false;
    currentSale.exists = true;

    // Transfer the funds to the company.
    require(token().transferFrom(msg.sender, address(this), sharesCap));

    // Enforce that one shareholder will remain majority.
    require(isMajorityShareholder(msg.sender));
  }

  /**
   * @dev Process the payment from the investor.
   */
  function processPayment()
    private
  {
    address investor = currentSale.investor;
    uint256 excessWei = 0;
    uint256 sharesSold = currentSale.sharesSold;
    uint256 sharesCap = currentSale.sharesCap;
    uint256 rate = currentSale.rate;
    uint256 weiAmount = msg.value;
    uint256 shares = weiAmount.mul(rate).div(1 ether);

    // If the after this investment the cap will be reached
    // the sale will end and the excess wei will be sent
    // back to the investor. 
    if (sharesSold.add(shares) > sharesCap) {
      excessWei = sharesSold.add(shares).sub(sharesCap).mul(1 ether).div(rate);
      weiAmount = weiAmount.sub(excessWei);
      shares = sharesCap.sub(sharesSold);
    } else {
      //we care of investors money
      excessWei = weiAmount.sub(shares.mul(1 ether).div(rate));
      weiAmount = weiAmount.sub(excessWei);
    }

    // update shares
    currentSale.sharesSold = sharesSold.add(shares);

    // update weiRaised.
    currentSale.weiRaised = currentSale.weiRaised.add(weiAmount);

    //close sale
    if(currentSale.sharesSold == sharesCap) {
      currentSale.ended = true;
      SaleEnded(now);
    }

    // Send tokens to the investor.
    require(token().transfer(investor, shares));

    // Send excess back to the investor.
    if (excessWei > 0) {
      investor.transfer(excessWei);
    }

    // Trigger event.
    ProcessedInvestment(investor, weiAmount, shares);
  }

  /**
   * @dev Finalize the in progress sale.
   */
  function finalizeSale()
    public
    isActive
    onlySaleCreator
    onlyWhenSelling
  {
    require(currentSale.ended);
    require(currentSale.sharesSold == currentSale.sharesCap);

    // Send wei to the beneficiary.
    currentSale.beneficiary.transfer(currentSale.weiRaised); 

    // Trigger event.
    SaleCompleted(currentSale.beneficiary, currentSale.weiRaised, currentSale.sharesSold);
    
    // Reset sale.
    currentSale.exists = false;
  }

  /**
   * @dev Abort the current sale.
   */
  function abortSale()
    public
    isActive
    onlySaleCreator
    onlyWhenSelling
  {
    require(!currentSale.ended);

    address investor = currentSale.investor;
    address shareholder = currentSale.shareholder;
    address company = address(this);

    // Send wei back to the investor.
    investor.transfer(currentSale.weiRaised);

    // Send tokens back from the investor to company.
    require(token().transferFrom(investor, company, currentSale.sharesSold));

    // Send tokens back from the company to the shareholder.
    require(token().transferFrom(company, shareholder, currentSale.sharesCap));

    // Trigger event.
    SaleAborted(now);

    // Reset sale state.
    currentSale.exists = false;
  }
}
function processPayment()
  private
{
  address investor = currentSale.investor;
  uint256 excessWei = 0;
  uint256 sharesSold = currentSale.sharesSold;
  uint256 sharesCap = currentSale.sharesCap;
  uint256 rate = currentSale.rate;
  uint256 weiAmount = msg.value;
  uint256 shares = weiAmount.mul(rate).div(1 ether);

  // If the after this investment the cap will be reached
  // the sale will end and the excess wei will be sent
  // back to the investor. 
  if (sharesSold.add(shares) > sharesCap) {
    excessWei = sharesSold.add(shares).sub(sharesCap).mul(1 ether).div(rate);
    weiAmount = weiAmount.sub(excessWei);
    shares = sharesCap.sub(sharesSold);
  } else {
    //we care of investors money
    excessWei = weiAmount.sub(shares.mul(1 ether).div(rate));
    weiAmount = weiAmount.sub(excessWei);
  }

  // update shares
  currentSale.sharesSold = sharesSold.add(shares);

  // update weiRaised.
  currentSale.weiRaised = currentSale.weiRaised.add(weiAmount);

  //close sale
  if(currentSale.sharesSold == sharesCap) {
    currentSale.ended = true;
    SaleEnded(now);
  }

  // Send tokens to the investor.
  require(token().transfer(investor, shares));

  // Send excess back to the investor.
  if (excessWei > 0) {
    investor.transfer(excessWei);
  }

  // Trigger event.
  ProcessedInvestment(investor, weiAmount, shares);
}

/**
 * @dev Process the payment from the investor.
 */