// Contract: CLIQWETHLPStaking
// Target function: function setManager(uint256 tokenStakingCount, uint256 tokenTotalDays, address tokenStakingAddress, uint256 tokenStakingStartTime,
//SPDX-License-Identifier:MIT
pragma solidity ^0.6.0;

/**
 * @title SafeMath
 * @dev   Unsigned math operations with safety checks that revert on error
 */
library SafeMath {
    
    /**
    * @dev Multiplies two unsigned integers, reverts on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256){
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b,"Calculation error");
        return c;
    }

    /**
    * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256){
        // Solidity only automatically asserts when dividing by 0
        require(b > 0,"Calculation error");
        uint256 c = a / b;
        return c;
    }

    /**
    * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256){
        require(b <= a,"Calculation error");
        uint256 c = a - b;
        return c;
    }

    /**
    * @dev Adds two unsigned integers, reverts on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256){
        uint256 c = a + b;
        require(c >= a,"Calculation error");
        return c;
    }

    /**
    * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
    * reverts when dividing by zero.
    */
    function mod(uint256 a, uint256 b) internal pure returns (uint256){
        require(b != 0,"Calculation error");
        return a % b;
    }
}

/**
 * @title ILPToken
 * @dev   Contract interface for LP token contract 
 */
abstract contract ILPToken {
    function balanceOf(address) public virtual returns (uint256);
    function transfer(address, uint256) public virtual returns (bool);
    function transferFrom(address, address, uint256) public virtual returns (bool);
    function approve(address , uint256) public virtual returns (bool);
 }

/**
 * @title IToken
 * @dev   Contract interface for token contract 
 */
abstract contract IToken {
    function balanceOf(address) public virtual returns (uint256);
    function transfer(address, uint256) public virtual returns (bool);
    function transferFrom(address, address, uint256) public virtual returns (bool);
    function approve(address , uint256) public virtual returns (bool);
 }

/**
 * @title CLIQWETHLPStaking
 * @dev   CLIQWETHLP Staking Contract for LP token staking
 */
contract CLIQWETHLPStaking {
    
  using SafeMath for uint256;

  address private _owner;                                           // variable for Owner of the Contract.
  uint256 private _withdrawTime;                                    // variable to manage withdraw time for Token
  uint256 constant public PERIOD_SILVER            = 90;             // variable constant for time period managemnt
  uint256 constant public PERIOD_GOLD              = 180;            // variable constant for time period managemnt
  uint256 constant public PERIOD_PLATINUM          = 270;            // variable constant for time period managemnt
  uint256 constant public WITHDRAW_TIME_SILVER     = 45 * 1 days;    // variable constant to manage withdraw time lock up 
  uint256 constant public WITHDRAW_TIME_GOLD       = 90 * 1 days;    // variable constant to manage withdraw time lock up
  uint256 constant public WITHDRAW_TIME_PLATINUM   = 135 * 1 days;   // variable constant to manage withdraw time lock up
  uint256 public TOKEN_REWARD_PERCENT_SILVER       = 21788328;       // variable constant to manage token reward percentage for silver
  uint256 public TOKEN_REWARD_PERCENT_GOLD         = 67332005;       // variable constant to manage token reward percentage for gold
  uint256 public TOKEN_REWARD_PERCENT_PLATINUM     = 178233538;      // variable constant to manage token reward percentage for platinum
  uint256 public TOKEN_PENALTY_PERCENT_SILVER      = 10894164;       // variable constant to manage token penalty percentage for silver
  uint256 public TOKEN_PENALTY_PERCENT_GOLD        = 23566201;       // variable constant to manage token penalty percentage for gold
  uint256 public TOKEN_PENALTY_PERCENT_PLATINUM    = 44558384;       // variable constant to manage token penalty percentage for platinum
  
  // events to handle staking pause or unpause for token 
  event Paused();
  event Unpaused();
  
  /*
  * ---------------------------------------------------------------------------------------------------------------------------
  * Functions for owner.
  * ---------------------------------------------------------------------------------------------------------------------------
  */

   /**
   * @dev get address of smart contract owner
   * @return address of owner
   */
   function getowner() public view returns (address) {
     return _owner;
   }

   /**
   * @dev modifier to check if the message sender is owner
   */
   modifier onlyOwner() {
     require(isOwner(),"You are not authenticate to make this transfer");
     _;
   }

   /**
   * @dev Internal function for modifier
   */
   function isOwner() internal view returns (bool) {
      return msg.sender == _owner;
   }

   /**
   * @dev Transfer ownership of the smart contract. For owner only
   * @return request status
   */
   function transferOwnership(address newOwner) public onlyOwner returns (bool){
      _owner = newOwner;
      return true;
   }
   
  /*
  * ---------------------------------------------------------------------------------------------------------------------------
  * Functionality of Constructor and Interface  
  * ---------------------------------------------------------------------------------------------------------------------------
  */
  
  // constructor to declare owner of the contract during time of deploy  
  constructor() public {
     _owner = msg.sender;
  }
  
  // Interface declaration for contract
  ILPToken ilptoken;
  IToken itoken;
    
  // function to set Contract Address for Token Transfer Functionality for LP Token and Cliq Token
  function setContractAddresses(address lpTokenContractAddress, address tokenContractAddress) external onlyOwner returns(bool){
    ilptoken = ILPToken(lpTokenContractAddress);
    itoken = IToken(tokenContractAddress);
    return true;
  }
  
   /*
  * ----------------------------------------------------------------------------------------------------------------------------
  * Owner functions of get value, set value and other Functionality
  * ----------------------------------------------------------------------------------------------------------------------------
  */
  
  // function to add token reward in contract
  function addTokenReward(uint256 token) external onlyOwner returns(bool){
    _ownerTokenAllowance = _ownerTokenAllowance.add(token);
    itoken.transferFrom(msg.sender, address(this), token);
    return true;
  }
  
  // function to withdraw added token reward in contract
  function withdrawAddedTokenReward(uint256 token) external onlyOwner returns(bool){
    require(token < _ownerTokenAllowance,"Value is not feasible, Please Try Again!!!");
    _ownerTokenAllowance = _ownerTokenAllowance.sub(token);
    itoken.transfer(msg.sender, token);
    return true;
  }
  
  // function to get token reward in contract
  function getTokenReward() public view returns(uint256){
    return _ownerTokenAllowance;
  }
  
  // function to pause Token Staking
  function pauseTokenStaking() public onlyOwner {
    tokenPaused = true;
    emit Paused();
  }

  // function to unpause Token Staking
  function unpauseTokenStaking() public onlyOwner {
    tokenPaused = false;
    emit Unpaused();
  }