pragma solidity >=0.5.0;

contract StonePaperScissors {
    address payable owner;

    struct room{
        address payable player1;
        address payable player2;
        bytes32 encryptedInput1;
        bytes32 encryptedInput2;
        string input1;
        string input2;
        string key1;
        string key2;
        address payable winner;
        bool done;
    }

    mapping (uint256 => room) rooms;


    bytes32 validStone = keccak256(abi.encodePacked("stone"));
    bytes32 validPaper = keccak256(abi.encodePacked("paper"));
    bytes32 validScissors = keccak256(abi.encodePacked("scissors"));

    uint256 constant betAmount = 10000000000000000; //0.01 Ether


    constructor()public{
        owner = msg.sender;
    }

    function createRoom() public payable {
        require(msg.value >= betAmount);
        uint256 roomId = uint256(msg.sender);
        rooms[roomId].player1 = msg.sender;
        rooms[roomId].player2 = address(0x0);
        rooms[roomId].encryptedInput1 = 0;
        rooms[roomId].encryptedInput2 = 0;
        rooms[roomId].input1 = "";
        rooms[roomId].input2 = "";
        rooms[roomId].key1 = "";
        rooms[roomId].key2 = "";
        rooms[roomId].winner = address(0x0);
        rooms[roomId].done = false;
    }


    function acceptInvitation(address roomOwner) public payable {
        require(msg.value >= betAmount);
        uint256 roomId = uint256(roomOwner);
        rooms[roomId].player2 = msg.sender;
    }

    function getWinner(address roomId) public view returns (address) {
        return rooms[uint256(roomId)].winner;
    }

    function getRoom(address roomId) public view returns (address player1, address player2, bytes32 encryptedInput1, bytes32 encryptedInput2, string memory input1, string memory input2, string memory key1, string memory key2, address winner) {
        room memory roo = rooms[uint256(roomId)];
        return (roo.player1, roo.player2, roo.encryptedInput1, roo.encryptedInput2, roo.input1, roo.input2, roo.key1, roo.key2, roo.winner);
    }

    function addInput(string memory input, string memory key, address roomId) public {
        require( msg.sender == rooms[uint256(roomId)].player1 || msg.sender == rooms[uint256(roomId)].player2, "You are not a active participant in this room!");
        if (msg.sender == rooms[uint256(roomId)].player1) {
            rooms[uint256(roomId)].encryptedInput1 = sha256(abi.encodePacked(input, key));
        }else {
            rooms[uint256(roomId)].encryptedInput2 = sha256(abi.encodePacked(input, key));
        }
    }

    function addKey(string memory key, address roomId, string memory input) public {
        require( msg.sender == rooms[uint256(roomId)].player1 || msg.sender == rooms[uint256(roomId)].player2, "You are not a active participant in this room!");
        if (msg.sender == rooms[uint256(roomId)].player1) {
            rooms[uint256(roomId)].key1 = key;
            rooms[uint256(roomId)].input1 = input;
        }else {
            rooms[uint256(roomId)].key2 = key;
            rooms[uint256(roomId)].input2 = input;
        }
    }

    function validateInputs(address roomId) public {
        if(rooms[uint256(roomId)].done == false){
			rooms[uint256(roomId)].done = true;
			bytes32 hash1 = sha256(abi.encodePacked(rooms[uint256(roomId)].input1, rooms[uint256(roomId)].key1));
			bytes32 hash2 = sha256(abi.encodePacked(rooms[uint256(roomId)].input2, rooms[uint256(roomId)].key2));
			if(hash1 == rooms[uint256(roomId)].encryptedInput1 && hash2 == rooms[uint256(roomId)].encryptedInput2){
				evaluateWinner(roomId, rooms[uint256(roomId)].input1,rooms[uint256(roomId)].input2);
			} else if(hash1 == rooms[uint256(roomId)].encryptedInput1 && hash2 != rooms[uint256(roomId)].encryptedInput2){
				rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player1;
			} else if(hash1 != rooms[uint256(roomId)].encryptedInput1 && hash2 == rooms[uint256(roomId)].encryptedInput2){
				rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player2;
			} else {
				rooms[uint256(roomId)].winner = owner;
				owner.transfer(2*betAmount);
			}
		}
    }

    function evaluateWinner(address roomId, string memory input1, string memory input2) public {
        bytes32 input1hash = keccak256(abi.encodePacked(input1));
        bytes32 input2hash = keccak256(abi.encodePacked(input2));
        if(input1hash == input2hash){
            rooms[uint256(roomId)].winner = address(0x1);
            rooms[uint256(roomId)].player1.transfer(betAmount);
            rooms[uint256(roomId)].player2.transfer(betAmount);

        } else if(input1hash == validPaper){
            if(input2hash == validStone){
                rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player1;
                rooms[uint256(roomId)].winner.transfer(2*betAmount);
            } else if(input2hash == validScissors){
                rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player2;
                rooms[uint256(roomId)].winner.transfer(2*betAmount);
            }
        } else if(input1hash == validStone){
            if(input2hash == validPaper){
                rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player2;
                rooms[uint256(roomId)].winner.transfer(2*betAmount);
            } else if(input2hash == validScissors){
                rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player1;
                rooms[uint256(roomId)].winner.transfer(2*betAmount);
            }
        } else if(input1hash == validScissors){
            if(input2hash == validPaper){
                rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player1;
                rooms[uint256(roomId)].winner.transfer(2*betAmount);

            } else if(input2hash == validStone){
                rooms[uint256(roomId)].winner = rooms[uint256(roomId)].player2;
                rooms[uint256(roomId)].winner.transfer(2*betAmount);
            }
        }
    }
}
