contract CryptoNumismat 
{
    
    using strings for *;
    
    address owner;

    string public standard = 'CryptoNumismat';
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;

    struct Buy 
    {
        uint cardIndex;
        address seller;
        uint minValue;  // in wei
        uint intName;
        string name;
    }
    
    struct UnitedBuy 
    {
        uint cardIndex;
        address seller;
        uint intName;
        string name;
    }

    mapping (uint => Buy) public cardsForSale;
    mapping (uint => UnitedBuy) public UnitedCardsForSale;
    mapping (address => bool) public admins;
    mapping (address => string) public nicknames;

    event Assign(uint indexed _cardIndex, address indexed _seller, uint256 _value, uint _intName, string _name);
    event Transfer(address indexed _from, address indexed _to, uint _cardIndex, uint256 _value);
    
    function CryptoNumismat() public payable 
    {
        owner = msg.sender;
        admins[owner] = true;
        
        totalSupply = 1000;                         // Update total supply
        name = "cryptonumismat";                    // Set the name for display purposes
        symbol = "$";                               // Set the symbol for display purposes
        decimals = 0;                               // Amount of decimals for display purposes
    }
    
    modifier onlyOwner() 
    {
        require(msg.sender == owner);
        _;
    }
    
    modifier onlyAdmins() 
    {
        require(admins[msg.sender]);
        _;
    }
    
    function setOwner(address _owner) onlyOwner() public 
    {
        owner = _owner;
    }
    
    function addAdmin(address _admin) onlyOwner() public
    {
        admins[_admin] = true;
    }
    
    function removeAdmin(address _admin) onlyOwner() public
    {
        delete admins[_admin];
    }
    
    function withdrawAll() onlyOwner() public 
    {
        owner.transfer(this.balance);
    }

    function withdrawAmount(uint256 _amount) onlyOwner() public 
    {
        require(_amount <= this.balance);
        
        owner.transfer(_amount);
    }
    
    /// _type == "Common"
    /// _type == "United"

    function addCard(string _type, uint _intName, string _name, uint _cardIndex, uint256 _value, address _ownAddress) public onlyAdmins()
    {
        require(_cardIndex <= 1000);
        require(_cardIndex > 0);
        
        require(cardsForSale[_cardIndex].cardIndex != _cardIndex);
        require(UnitedCardsForSale[_intName].intName != _intName);
        
        address seller = _ownAddress;
        uint256 _value2 = (_value * 1000000000);
        
        if (strings.equals(_type.toSlice(), "Common".toSlice()))
        {
            cardsForSale[_cardIndex] = Buy(_cardIndex, seller, _value2, _intName, _name);
            Assign(_cardIndex, seller, _value2, _intName, _name);
        }
        else if (strings.equals(_type.toSlice(), "United".toSlice()))
        {
            UnitedCardsForSale[_intName] = UnitedBuy(_cardIndex, seller, _intName, _name);
            cardsForSale[_cardIndex] = Buy(_cardIndex, seller, _value2,  _intName, _name);
            Assign(_cardIndex, seller, _value2, _intName, _name);
        }
    }
    
    function displayCard(uint _cardIndex) public constant returns(uint, address, uint256, uint, string) 
    {
        require(_cardIndex <= 1000);
        require(_cardIndex > 0);
        
        require (cardsForSale[_cardIndex].cardIndex == _cardIndex);
            
        return(cardsForSale[_cardIndex].cardIndex, 
        cardsForSale[_cardIndex].seller,
        cardsForSale[_cardIndex].minValue,
        cardsForSale[_cardIndex].intName,
        cardsForSale[_cardIndex].name);
    }
    
    function setNick(string _newNick) public
    {
        nicknames[msg.sender] = _newNick;      
    }
    
    function displayNick(address _owner) public constant returns(string)
    {
        return nicknames[_owner];
    }
    
    
    uint256 private limit1 = 0.05 ether;
    uint256 private limit2 = 0.5 ether;
    uint256 private limit3 = 5 ether;
    uint256 private limit4 = 50 ether;
    
    function calculateNextPrice(uint256 _startPrice) public constant returns (uint256 _finalPrice)
    {
        if (_startPrice < limit1)
            _startPrice =  _startPrice * 10 / 4;
        else if (_startPrice < limit2)
            _startPrice =  _startPrice * 10 / 5;
        else if (_startPrice < limit3)
            _startPrice =  _startPrice * 10 / 6;
        else if (_startPrice < limit4)
            _startPrice =  _startPrice * 10 / 7;
        else
            _startPrice =  _startPrice * 10 / 8;
            
        return (_startPrice / 1000000) * 1000000;
    }
    
    function calculateDevCut(uint256 _startPrice) public constant returns (uint256 _cut)
    {
        if (_startPrice < limit2)
            _startPrice =  _startPrice * 5 / 100;
        else if (_startPrice < limit3)
            _startPrice =  _startPrice * 4 / 100;
        else if (_startPrice < limit4)
            _startPrice =  _startPrice * 3 / 100;
        else
            _startPrice =  _startPrice * 2 / 100;
            
        return (_startPrice / 1000000) * 1000000;
    }
    
    function buy(uint _cardIndex) public payable
    {
        require(_cardIndex <= 1000);
        require(_cardIndex > 0);
        require(cardsForSale[_cardIndex].cardIndex == _cardIndex);
        require(cardsForSale[_cardIndex].seller != msg.sender);
        require(msg.sender != address(0));
        require(msg.sender != owner);
        require(cardsForSale[_cardIndex].minValue > 0);
        require(msg.value >= cardsForSale[_cardIndex].minValue);
        
        address _buyer = msg.sender;
        address _seller = cardsForSale[_cardIndex].seller;
        string _name = cardsForSale[_cardIndex].name;
        uint _intName = cardsForSale[_cardIndex].intName;
        
        address _UnitedOwner = UnitedCardsForSale[_intName].seller;
        
        uint256 _price = cardsForSale[_cardIndex].minValue;
        
        uint256 _nextPrice = calculateNextPrice(_price);
        uint256 _devCut = calculateDevCut(_price);
        
        uint256 _totalPrice = _price - _devCut - (_devCut / 4);
        uint256 _extra = msg.value - _price;
        
        _seller.transfer(_totalPrice);
        _UnitedOwner.transfer((_devCut / 4));
        
        if (_extra > 0)
        {
            Transfer(_buyer, _buyer, _cardIndex, _extra);
            
            _buyer.transfer(_extra);
        }
        
        cardsForSale[_cardIndex].seller = _buyer;
        cardsForSale[_cardIndex].minValue = _nextPrice;
        
        if (_cardIndex == UnitedCardsForSale[_intName].cardIndex)
            UnitedCardsForSale[_intName].seller = _buyer;
        
        
        Transfer(_buyer, _seller, _cardIndex, _totalPrice);
        Assign(_cardIndex, _buyer, _nextPrice, _intName, _name);////////////////////////////////
    }
}
function addCard(string _type, uint _intName, string _name, uint _cardIndex, uint256 _value, address _ownAddress) public onlyAdmins()
{
    require(_cardIndex <= 1000);
    require(_cardIndex > 0);
        
    require(cardsForSale[_cardIndex].cardIndex != _cardIndex);
    require(UnitedCardsForSale[_intName].intName != _intName);
        
    address seller = _ownAddress;
    uint256 _value2 = (_value * 1000000000);
        
    if (strings.equals(_type.toSlice(), "Common".toSlice()))
    {
        cardsForSale[_cardIndex] = Buy(_cardIndex, seller, _value2, _intName, _name);
        Assign(_cardIndex, seller, _value2, _intName, _name);
    }
    else if (strings.equals(_type.toSlice(), "United".toSlice()))
    {
        UnitedCardsForSale[_intName] = UnitedBuy(_cardIndex, seller, _intName, _name);
        cardsForSale[_cardIndex] = Buy(_cardIndex, seller, _value2,  _intName, _name);
        Assign(_cardIndex, seller, _value2, _intName, _name);
    }
}

/// _type == "Common"
/// _type == "United"