library ProposalLibrary {
  //
  // structs
  //

  // tokenのstorage/associationを参照するための構造体
  struct Entity {
    IkuraStorage _storage;
    IkuraAssociation _association;
  }

  /**
   * 永続化ストレージを設定する
   *
   * @param self 実行Entity
   * @param storage_ 永続化ストレージのインスタンス（アドレス）
   */
  function changeStorage(Entity storage self, address storage_) internal {
    self._storage = IkuraStorage(storage_);
  }

  /**
   * 関連づける承認プロセスを変更する
   *
   * @param self 実行Entity
   * @param association_ 新しい承認プロセス
   */
  function changeAssociation(Entity storage self, address association_) internal {
    self._association = IkuraAssociation(association_);
  }

  /**
   * dJPYを鋳造する
   *
   * - コマンドを実行したユーザがオーナーである
   * - 鋳造する量が0より大きい
   *
   * 場合は成功する
   *
   * @param self 実行Entity
   * @param sender 実行アドレス
   * @param amount 鋳造する金額
   */
  function mint(Entity storage self, address sender, uint amount) public returns (bool) {
    require(amount > 0);

    self._association.newProposal(keccak256('mint'), sender, amount, '');

    return true;
  }

  /**
   * dJPYを消却する
   *
   * - コマンドを実行したユーザがオーナーである
   * - 鋳造する量が0より大きい
   * - dJPYの残高がamountよりも大きい
   * - SHINJIをamountよりも大きい
   *
   * 場合は成功する
   *
   * @param self 実行Entity
   * @param sender 実行アドレス
   * @param amount 消却する金額
   */
  function burn(Entity storage self, address sender, uint amount) public returns (bool) {
    require(amount > 0);
    require(self._storage.coinBalance(sender) >= amount);
    require(self._storage.tokenBalance(sender) >= amount);

    self._association.newProposal(keccak256('burn'), sender, amount, '');

    return true;
  }

  /**
   * 提案を承認する。
   * #TODO proposalIdは分からないので、別のものからproposalを特定しないといかんよ
   *
   * @param self 実行Entity
   * @param sender 実行アドレス
   * @param type_ 承認する提案の種類
   * @param proposalId 提案ID
   */
  function confirmProposal(Entity storage self, address sender, bytes32 type_, uint proposalId) public {
    self._association.confirmProposal(type_, sender, proposalId);
  }

  /**
   * 指定した種類の提案数を取得する
   *
   * @param type_ 提案の種類（'mint' | 'burn' | 'transferMinimumFee' | 'transferFeeRate'）
   *
   * @return 提案数（承認されていないものも含む）
   */
  function numberOfProposals(Entity storage self, bytes32 type_) public view returns (uint) {
    return self._association.numberOfProposals(type_);
  }
}
/**
 *
 * 承認プロセスの実装ライブラリ
 * IkuraTokenに実装するとサイズ超過してしまうため、ライブラリとして切り出している
 *
 * 今のところギリギリおさまっているので使ってはいない
 */
function changeAssociation(Entity storage self, address association_) internal {
  self._association = IkuraAssociation(association_);
}

/**
 * 関連づける承認プロセスを変更する
 *
 * @param self 実行Entity
 * @param association_ 新しい承認プロセス
 */