#include <stdio.h>
#include <unistd.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include "Pos.h"
#include "sha1.h"
#include <iostream>

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace pos;

using namespace boost;

int main(int argc, char** argv) {
  if (argc != 2) {
    cout << "Usage: client <host>\n";
    exit(1);
  }
  shared_ptr<TTransport> socket(new TSocket(argv[1], 9090));
  shared_ptr<TTransport> transport(new TFramedTransport(socket));
  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  PosClient client(protocol);

  try {
    transport->open();
  } catch(TException & e) {
    std::cerr << e.what() << "\n";
  }

  string s;
  std::cout << "(0) Exit\n"
               "(1) Add card to member\n"
               "(2) Register new product\n"
               "(3) Buy a product\n"
               "(4) Deposit money\n"
               "(5) Print balance\n"
               "(6) Set price of product\n";
  while(1) {
    cout << "> ";
    uint32_t in;
    std::cin >> in;
    switch(in) {
      case 0: exit(0);
      case 1: {
        string user, card;
        cout << "Username: ";
        cin >> user;
        cout << "Swipe card: ";
        getline(cin,s);
        getline(cin,card);
        client.getSalt(s);
        s = SHA1Hash(s+"PSK").toHex();
        client.associateHashWithName(s, card, user);
        break;
      }
      case 2: {
        uint64_t upc;
		cout << "UPC: ";
		cin >> upc;

		int32_t price;
		cout << "price: ";
		cin >> price;

		client.getSalt(s);
		s = SHA1Hash(s+"PSK").toHex();
		client.setUPCPrice(s, upc, price);
        break;
      }
      case 3: {
        string user;
        uint64_t upc;
        cout << "UPC: ";
        cin >> upc;
        int32_t price = client.getUPCPrice(upc);
        cout << "\tThe price is " << (double)price/100.0 << "\n";
        cout << "Username: ";
        cin >> user;
        int32_t balance = client.getNameAccountBalance(user);
        if (balance > price) {
          cout << "\tYour balance is " << (double)balance/100.0 << ", buying... \n";
        } else {
          cout << "Insufficient balance!\n";
          break;
        }
        client.getSalt(s);
        s = SHA1Hash(s+"PSK").toHex();
        client.doTransactionOnName(s, user, -price);
        client.getSalt(s);
        s = SHA1Hash(s+"PSK").toHex();
        client.doStockChange(s, upc, -1);
        balance = client.getNameAccountBalance(user);
        cout << "\tNew balance is " << (double)balance/100.0f << ".\n";
        break;
      }
      case 4: {
        string user;
        double delta; //lol
        cout << "Username: ";
        cin >> user;
        cout << "Amount to change balance by in dollars: ";
        cin >> delta;
        client.getSalt(s);
        s = SHA1Hash(s+"PSK").toHex();
        client.doTransactionOnName(s, user, (int)(100.0*delta));
        break;
      }
      case 5: {
        string user;
        cout << "Username: ";
        cin >> user;
        cout << "$" << ((double)client.getNameAccountBalance(user))/100.0 << "\n";
        break;
      }
      case 6: {
        double f;
        uint64_t upc;
        cout << "UPC: ";
        cin >> upc;
        cout << "Price: ";
        cin >> f;
        client.getSalt(s);
        s = SHA1Hash(s+"PSK").toHex();
        client.setUPCPrice(s, upc, (int32_t)(f*100.0));
        break;
      }
    }
    cout <<"\n";
  }



  for (uint32_t i =0; i < 5000; i++) {
    std::string s;
    client.getSalt(s);
    s = SHA1Hash(s + "PSK").toHex();
    client.doTransactionOnName(s, "j3parker", 1);
  }


  cout << "j3parker balance: " << client.getNameAccountBalance("j3parker") << "\n";
  cout << "m4burns balance: " << client.getNameAccountBalance("m4burns") << "\n";

  return 0;
}

