contract Transaction is Ownable {
  // custom types
  struct TransactionNeoPlace {
    uint id;
    address seller;
    address buyer;
    bytes16 itemId;
    bytes8 typeItem;
    string location;
    string pictureHash;
    bytes16 receiptHash;
    string comment;
    bytes8 status;
    uint256 _price;
  }

  // state variables
  mapping(uint => TransactionNeoPlace) public transactions;
  mapping(bytes16 => uint256) public fundsLocked;

  uint transactionCounter;

  // events
  event BuyItem(
    uint indexed _id,
    bytes16 indexed _itemId,
    address _seller,
    address _buyer,
    uint256 _price
  );

  function kill() public onlyOwner {
    selfdestruct(owner);
  }

  // fetch the number of transactions in the contract
  function getNumberOfTransactions() public view returns (uint) {
    return transactionCounter;
  }

  // fetch and return all sales of the seller
  function getSales() public view returns (uint[]) {
    // prepare output array
    uint[] memory transactionIds = new uint[](transactionCounter);

    uint numberOfSales = 0;

    // iterate over transactions
    for(uint i = 1; i <= transactionCounter; i++) {
      // keep the ID if the transaction owns to the seller
      if(transactions[i].seller == msg.sender) {
        transactionIds[numberOfSales] = transactions[i].id;
        numberOfSales++;
      }
    }

    // copy the transactionIds array into a smaller getSales array
    uint[] memory sales = new uint[](numberOfSales);
    for(uint j = 0; j < numberOfSales; j++) {
      sales[j] = transactionIds[j];
    }
    return sales;
  }

  // fetch and return all purchases of the buyer
  function getPurchases() public view returns (uint[]) {
    // prepare output array
    uint[] memory transactionIds = new uint[](transactionCounter);

    uint numberOfBuy = 0;

    // iterate over transactions
    for(uint i = 1; i <= transactionCounter; i++) {
      // keep the ID if the transaction owns to the seller
      if(transactions[i].buyer == msg.sender) {
        transactionIds[numberOfBuy] = transactions[i].id;
        numberOfBuy++;
      }
    }

    // copy the transactionIds array into a smaller getBuy array
    uint[] memory buy = new uint[](numberOfBuy);
    for(uint j = 0; j < numberOfBuy; j++) {
      buy[j] = transactionIds[j];
    }
    return buy;
  }

  // new transaction / buy item
  function buyItem(address _seller, bytes16 _itemId, bytes8 _typeItem, string _location, string _pictureHash, string _comment, bytes8 _status, uint256 _price) payable public {
    // address not null
    require(_seller != 0x0);
    // seller don't allow to buy his own item
    require(msg.sender != _seller);

    require(_itemId.length > 0);
    require(_typeItem.length > 0);
    require(bytes(_location).length > 0);
    require(bytes(_pictureHash).length > 0);
    //require(bytes(_comment).length > 0);

    require(msg.value == _price);


    // lock and put the funds in escrow
    //_seller.transfer(msg.value);
    fundsLocked[_itemId]=fundsLocked[_itemId] + _price;

    // new transaction
    transactionCounter++;

    // store the new transaction
    transactions[transactionCounter] = TransactionNeoPlace(
      transactionCounter,
      _seller,
      msg.sender,
      _itemId,
      _typeItem,
      _location,
      _pictureHash,
      "",
      _comment,
      _status,
      _price
    );

    // trigger the new transaction
    BuyItem(transactionCounter, _itemId, _seller, msg.sender, _price);
  }

  // send additional funds
  //TODO merge with unlockFunds
  function sendAdditionalFunds(address _seller, bytes16 _itemId, uint256 _price) payable public {
    // address not null
    require(_seller != 0x0);
    // seller don't allow to buy his own item
    require(msg.sender != _seller);

    require(_itemId.length > 0);

    require(msg.value == _price);

    for(uint i = 0; i <= transactionCounter; i++) {
      if(transactions[i].itemId == _itemId) {

        require(msg.sender == transactions[i].buyer);
        require(stringToBytes8("paid") == transactions[i].status);
        address seller = transactions[i].seller;
        transactions[i]._price = transactions[i]._price + msg.value;

        //transfer fund from client to vendor
        seller.transfer(msg.value);

        break;
      }
    }
  }

  function unlockFunds(bytes16 _itemId) public {

    for(uint i = 0; i <= transactionCounter; i++) {
      if(transactions[i].itemId == _itemId) {

        require(msg.sender == transactions[i].buyer);
        require(stringToBytes8("paid") != transactions[i].status);
        address buyer = transactions[i].buyer;
        address seller = transactions[i].seller;
        uint256 priceTransaction = transactions[i]._price;

        require(fundsLocked[_itemId]>0);
        fundsLocked[_itemId]=fundsLocked[_itemId] - (priceTransaction);

        //transfer fund from client to vendor
        seller.transfer(priceTransaction);

        transactions[i].status = stringToBytes8('paid');

        break;
      }
    }
  }

   function sendAmount(address seller) payable public {
      // address not null
      require(seller != 0x0);
      // seller don't allow to buy his own item
      require(msg.sender != seller);

      seller.transfer(msg.value);
   }

  function stringToBytes8(string memory source) returns (bytes8 result) {
    bytes memory tempEmptyStringTest = bytes(source);
    if (tempEmptyStringTest.length == 0) {
      return 0x0;
    }

    assembly {
      result := mload(add(source, 8))
    }
  }

}
function buyItem(address _seller, bytes16 _itemId, bytes8 _typeItem, string _location, string _pictureHash, string _comment, bytes8 _status, uint256 _price) payable public {
  // address not null
  require(_seller != 0x0);
  // seller don't allow to buy his own item
  require(msg.sender != _seller);

  require(_itemId.length > 0);
  require(_typeItem.length > 0);
  require(bytes(_location).length > 0);
  require(bytes(_pictureHash).length > 0);
  //require(bytes(_comment).length > 0);

  require(msg.value == _price);


  // lock and put the funds in escrow
  //_seller.transfer(msg.value);
  fundsLocked[_itemId]=fundsLocked[_itemId] + _price;

  // new transaction
  transactionCounter++;

  // store the new transaction
  transactions[transactionCounter] = TransactionNeoPlace(
    transactionCounter,
    _seller,
    msg.sender,
    _itemId,
    _typeItem,
    _location,
    _pictureHash,
    "",
    _comment,
    _status,
    _price
  );

  // trigger the new transaction
  BuyItem(transactionCounter, _itemId, _seller, msg.sender, _price);
}

// new transaction / buy item