contract Chainy is owned, mortal {
    string constant CHAINY_URL = "https://txn.me/";

    // Configuration
    mapping(string => uint256) private chainyConfig;

    // Service accounts
    mapping (address => bool) private srvAccount;

    // Fee receiver
    address private receiverAddress;

    struct data {uint256 timestamp; string json; address sender;}
    mapping (string => data) private chainy;

    event chainyShortLink(uint256 timestamp, string code);

    // Constructor
    function Chainy(){
        setConfig("fee", 0);
        setConfig("blockoffset", 1000000);
    }

    // Sets configuration option
    function setConfig(string _key, uint256 _value) onlyOwner {
        chainyConfig[_key] = _value;
    }

    // Returns configuration option
    function getConfig(string _key) constant returns (uint256 _value) {
        return chainyConfig[_key];
    }

    // Add/Remove service account
    function setServiceAccount(address _address, bool _value) onlyOwner {
        srvAccount[_address] = _value;
    }

    // Set receiver address
    function setReceiverAddress(address _address) onlyOwner {
        receiverAddress = _address;
    }

    // Add record
    function addChainyData(string json) {
        checkFormat(json);

        var code = generateShortLink();
        // Checks if the record exist
        if (getChainyTimestamp(code) > 0) throw;

        processFee();
        chainy[code] = data({
            timestamp: block.timestamp,
            json: json,
            sender: tx.origin
        });

        // Fire event
        var link = strUtils.concat(CHAINY_URL, code);
        chainyShortLink(block.timestamp, link);
    }

    // Get record timestamp
    function getChainyTimestamp(string code) constant returns (uint256) {
        return chainy[code].timestamp;
    }

    // Get record JSON
    function getChainyData(string code) constant returns (string) {
        return chainy[code].json;
    }

    // Get record sender
    function getChainySender(string code) constant returns (address) {
        return chainy[code].sender;
    }

    // Checks if enough fee provided
    function processFee() internal {
        var fee = getConfig("fee");
        if (srvAccount[msg.sender] || (fee == 0)) return;

        if (msg.value < fee)
            throw;
        else
            if (!receiverAddress.send(fee)) throw;
    }

    // Checks if provided string has valid format
    function checkFormat(string json) internal {
        if (!strUtils.isValidChainyJson(json)) throw;
    }

    function generateShortLink() internal returns (string) {
        var s1 = strUtils.toBase58(block.number - getConfig("blockoffset"), 10);
        var s2 = strUtils.toBase58(uint256(tx.origin), 2);

        var s = strUtils.concat(s1, s2);
        return s;
    }

}
function setConfig(string _key, uint256 _value) onlyOwner {
    chainyConfig[_key] = _value;
}

// Sets configuration option