contract ProductsListStorage is UintIteratorStorage, ResolverClient, DigixConstants {

  using DoublyLinkedList for DoublyLinkedList.Uint;

  struct System {
    mapping (uint256 => Product) products_by_id;
    DoublyLinkedList.Uint products_list;
  }

  struct Product {
    bytes32 document;
    bool enabled;
    uint256 ng_weight;
    uint256 effective_ng_weight;
  }

  System system;

  function ProductsListStorage(address _resolver) public
  {
    require(init(CONTRACT_STORAGE_PRODUCTS_LIST, _resolver));
  }

  /// @notice add a new product to the product list
  /// @param _document the dijix ipfs document
  /// @param _ng_weight the weight of the product
  /// @param _effective_ng_weight the effective weight of the product
  /// @return _success whether the product is successfully added
  /// @return _product_id the product id of the newly created product
  function create_product(bytes32 _document, uint256 _ng_weight, uint256 _effective_ng_weight)
           if_sender_is(CONTRACT_CONTROLLER_PRODUCTS_LIST)
           public
           returns (bool _success, uint256 _product_id)
  {
    require(_ng_weight > 0);
    require(_effective_ng_weight > 0);
    _product_id = system.products_list.total() + 1;
    system.products_by_id[_product_id].enabled = true;
    system.products_by_id[_product_id].document = _document;
    system.products_by_id[_product_id].ng_weight = _ng_weight;
    system.products_by_id[_product_id].effective_ng_weight = _effective_ng_weight;
    _success = system.products_list.append(_product_id);
  }

  /// @notice enable an existing disabled product in the product list
  /// @param _product_id the product id
  /// @return _success whether the product is successfully enabled
  function enable_product(uint256 _product_id)
           if_sender_is(CONTRACT_CONTROLLER_PRODUCTS_LIST)
           public
           returns (bool _success)
  {
    if (system.products_by_id[_product_id].enabled == true || system.products_by_id[_product_id].ng_weight == 0 ) {
      // if product is already enabled or product doesnt exist
      _success = false;
    } else {
      system.products_by_id[_product_id].enabled = true;
      _success = true;
    }
  }

  /// @notice disable an existing enabled product in the product list
  /// @param _product_id the product id
  /// @return _success whether the product is successfully disabled
  function disable_product(uint256 _product_id)
           if_sender_is(CONTRACT_CONTROLLER_PRODUCTS_LIST)
           public
           returns (bool _success)
  {
    if (system.products_by_id[_product_id].enabled == false) {
      _success = false;
    } else {
      system.products_by_id[_product_id].enabled = false;
      _success = true;
    }
  }


  /// @notice read information of an existing product
  /// @param _product_id the product id
  /// @return _document the dijix ipfs document
  /// @return _ng_weight the weight of the product
  /// @return _effective_ng_weight the effective weight of the product
  /// @return _enabled whether the product is enabled
  function read_product(uint256 _product_id)
           public
           constant
           returns (bytes32 _document, uint256 _ng_weight, uint256 _effective_ng_weight, bool _enabled)
  {
    if (system.products_by_id[_product_id].enabled == true) {
      _ng_weight = system.products_by_id[_product_id].ng_weight;
      _effective_ng_weight = system.products_by_id[_product_id].effective_ng_weight;
      _enabled = system.products_by_id[_product_id].enabled;
      _document = system.products_by_id[_product_id].document;
    } else {
      _ng_weight = 0;
      _effective_ng_weight = 0;
      _enabled = system.products_by_id[_product_id].enabled;
      _document = "";
    }
  }

  /// @notice read weight and effective weight of an existing product
  /// @param _product_id the product id
  /// @return _ng_weight the weight of the product
  /// @return _effective_ng_weight the effective weight of the product
  function read_product_ng_weight_and_effective_ng_weight(uint256 _product_id)
           public
           constant
           returns (uint256 _ng_weight, uint256 _effective_ng_weight)
  {
    if (system.products_by_id[_product_id].enabled == true) {
      _ng_weight = system.products_by_id[_product_id].ng_weight;
      _effective_ng_weight = system.products_by_id[_product_id].effective_ng_weight;
    } else {
      _ng_weight = 0;
      _effective_ng_weight = 0;
    }
  }

  /// @notice read the total number of products in product list
  /// @return _total_count total number of products
  function read_products_total()
           public
           constant
           returns (uint256 _total_count)
  {
    _total_count = read_total_uints(system.products_list);
  }

  /// @notice read the first product in product list
  /// @return _item first product
  function read_first_product()
           public
           constant
           returns (uint256 _item)
  {
    _item = read_first_from_uints(system.products_list);
  }

  /// @notice read the last product in product list
  /// @return _item last product
  function read_last_product()
           public
           constant
           returns (uint256 _item)
  {
    _item = read_last_from_uints(system.products_list);
  }

  /// @notice read the next product after some product
  /// @param _current_item the current item
  /// @return _item next product
  function read_next_from_product(uint256 _current_item)
           public
           constant
           returns (uint256 _item)
  {
    _item = read_next_from_uints(system.products_list, _current_item);
  }

  /// @notice read the previous product after some product
  /// @param _current_item the current item
  /// @return _item previous product
  function read_previous_from_product(uint256 _current_item)
           public
           constant
           returns (uint256 _item)
  {
    _item = read_previous_from_uints(system.products_list, _current_item);
  }
}
function read_product_ng_weight_and_effective_ng_weight(uint256 _product_id)
         public
         constant
         returns (uint256 _ng_weight, uint256 _effective_ng_weight)
{
  if (system.products_by_id[_product_id].enabled == true) {
    _ng_weight = system.products_by_id[_product_id].ng_weight;
    _effective_ng_weight = system.products_by_id[_product_id].effective_ng_weight;
  } else {
    _ng_weight = 0;
    _effective_ng_weight = 0;
  }
}

/// @notice read weight and effective weight of an existing product
/// @param _product_id the product id
/// @return _ng_weight the weight of the product
/// @return _effective_ng_weight the effective weight of the product