#include "bridge-soln.hh"
#include <iostream>
#include "ostreamlock.h"
#include <algorithm>
#include <iomanip>

using namespace std;

void Bridge::arrive_eastbound(size_t id) {
    bridge_lock.lock();
    print(id, "arrived", true);
    while (n_crossing_westbound > 0) {
        none_crossing_westbound.wait(bridge_lock);
    }
    n_crossing_eastbound++;
    print(id, "crossing", true);
    bridge_lock.unlock();
}

void Bridge::leave_eastbound(size_t id) {
    bridge_lock.lock();
    n_crossing_eastbound--;
    if (n_crossing_eastbound == 0) {
        none_crossing_eastbound.notify_all();
    }
    print(id, "crossed", true);
    bridge_lock.unlock();
}

void Bridge::arrive_westbound(size_t id) {
    bridge_lock.lock();
    print(id, "arrived", false);
    while (n_crossing_eastbound > 0) {
        none_crossing_eastbound.wait(bridge_lock);
    }
    n_crossing_westbound++;
    print(id, "crossing", false);
    bridge_lock.unlock();
}

void Bridge::leave_westbound(size_t id) {
    bridge_lock.lock();
    n_crossing_westbound--;
    if (n_crossing_westbound == 0) {
        none_crossing_westbound.notify_all();
    }
    print(id, "crossed", false);
    bridge_lock.unlock();
}

void Bridge::print(size_t id, const string& message, bool isEastbound) {
    // Make a single string to contain e.g. "car #XX crossing going eastbound".
    // This must be a single string to right-align the BRIDGE graphic correctly.
    ostringstream ss;
    ss << "car #" << id << " " << message << " going " 
       << (isEastbound ? "eastbound" : "westbound");
    string statusMessage = ss.str();

    // Print the update, spaced equally so that the BRIDGE prints at the same
    // position on the line, no matter the length of the message.
    cout << oslock << setw(60) << left << statusMessage;

    // Now print the text representation of the bridge
    if (n_crossing_eastbound + n_crossing_westbound == 0) {
        cout << "BRIDGE: [none crossing]" << endl << osunlock;
    } else if (n_crossing_eastbound > 0 && n_crossing_westbound == 0) {
        cout << "BRIDGE: [";
        for (size_t i = 0; i < n_crossing_eastbound; i++) cout << "🚗";
        cout << " -->>]" << endl << osunlock;
    } else if (n_crossing_westbound > 0 && n_crossing_eastbound == 0) {
        cout << "BRIDGE: [<<-- ";
        for (size_t i = 0; i < n_crossing_westbound; i++) cout << "🚙";
        cout << "]" << endl << osunlock;
    } else {
        cout << "ERROR!!  cars stuck, trying to go both directions" << endl << osunlock;
    }
}
