// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library MintMakerTest;
import 'dart:async';
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';

class Mint {
  Map<SendPort, Purse> _registry;
  SendPort port;

  Mint() : _registry = new Map<SendPort, Purse>() {
    ReceivePort mintPort = new ReceivePort();
    port = mintPort.sendPort;
    serveMint(mintPort);
  }

  void serveMint(ReceivePort port) {
    port.listen((message) {
      int balance = message[0];
      Purse purse = createPurse(balance);
      message[1].send(purse.port);
    });
  }

  Purse createPurse(int balance) {
    Purse purse = new Purse(this, balance);
    _registry[purse.port] = purse;
    return purse;
  }

  Purse lookupPurse(SendPort port) {
    return _registry[port];
  }
}


class MintWrapper {
  SendPort _mint;
  MintWrapper(SendPort this._mint) {}

  void createPurse(int balance, handlePurse(PurseWrapper purse)) {
    ReceivePort reply = new ReceivePort();
    reply.first.then((SendPort purse) {
      handlePurse(new PurseWrapper(purse));
    });
    _mint.send([balance, reply.sendPort]);
  }

}

class Purse {
  Mint mint;
  int balance;
  SendPort port;

  Purse(this.mint, this.balance) {
    ReceivePort recipient = new ReceivePort();
    port = recipient.sendPort;
    servePurse(recipient);
  }

  void servePurse(ReceivePort recipient) {
    recipient.listen((message) {
      String command = message[0];
      if (command == "balance") {
        SendPort replyTo = message.last;
        replyTo.send(queryBalance());
      } else if (command == "deposit") {
        Purse source = mint.lookupPurse(message[2]);
        deposit(message[1], source);
      } else if (command == "sprout") {
        SendPort replyTo = message.last;
        Purse result = sproutPurse();
        replyTo.send(result.port);
      } else {
        // TODO: Send an exception back.
        throw UnsupportedError("Unsupported commend: $command");
      }
    });
  }

  int queryBalance() { return balance; }

  Purse sproutPurse() { return mint.createPurse(0); }

  void deposit(int amount, Purse source) {
    // TODO: Throw an exception if the source purse doesn't hold
    // enough dough.
    balance += amount;
    source.balance -= amount;
  }
}


class PurseWrapper {
  SendPort _purse;

  PurseWrapper(this._purse) {}

  void _sendReceive(message, replyHandler(reply)) {
    ReceivePort reply = new ReceivePort();
    _purse.send([message, reply.sendPort]);
    reply.first.then(replyHandler);
  }

  void queryBalance(handleBalance(int balance)) {
    _sendReceive("balance", handleBalance);
  }

  void sproutPurse(handleSprouted(PurseWrapper sprouted)) {
    _sendReceive("sprout", (SendPort sprouted) {
      handleSprouted(new PurseWrapper(sprouted));
    });
  }

  void deposit(PurseWrapper source, int amount) {
    _purse.send([ "deposit", amount, source._purse ]);
  }
}

mintMakerWrapper(SendPort replyPort) {
  ReceivePort receiver = new ReceivePort();
  replyPort.send(receiver.sendPort);
  receiver.listen((SendPort replyTo) {
    Mint mint = new Mint();
    replyTo.send(mint.port);
  });
}

class MintMakerWrapper {
  final SendPort _port;

  static Future<MintMakerWrapper> create() {
    ReceivePort reply = new ReceivePort();
    return Isolate.spawn(mintMakerWrapper, reply.sendPort).then((_) =>
        reply.first.then((port) => new MintMakerWrapper._(port)));
  }

  MintMakerWrapper._(this._port);

  void makeMint(handleMint(MintWrapper mint)) {
    ReceivePort reply = new ReceivePort();
    reply.first.then((SendPort mint) { handleMint(new MintWrapper(mint)); });
    _port.send(reply.sendPort);
  }
}

_checkBalance(PurseWrapper wrapper, expected) {
  wrapper.queryBalance(expectAsync1((int balance) {
    expect(balance, equals(expected));
  }));
}

main() {
  test("creating purse, deposit, and query balance", () {
    MintMakerWrapper.create().then(expectAsync1((mintMaker) {
      mintMaker.makeMint(expectAsync1((MintWrapper mint) {
        mint.createPurse(100, expectAsync1((PurseWrapper purse) {
          _checkBalance(purse, 100);
          purse.sproutPurse(expectAsync1((PurseWrapper sprouted) {
            _checkBalance(sprouted, 0);
            _checkBalance(purse, 100);

            sprouted.deposit(purse, 5);
            _checkBalance(sprouted, 0 + 5);
            _checkBalance(purse, 100 - 5);

            sprouted.deposit(purse, 42);
            _checkBalance(sprouted, 0 + 5 + 42);
            _checkBalance(purse, 100 - 5 - 42);
          }));
        }));
      }));
    }));
  });
}
