#define MAXCOLORTC
#include "wingraph.h"

const int cc = RGB (197, 203, 201); // разные цвета
const int ca = RGB (196, 244, 203);
const int cb = RGB (255, 248, 127);
const int cw = RGB (255, 255, 255);

struct LongMsg // структура для передачи информации от пункта заготовления топлива
{                           // транспортному средству
  int w;              // вес топлива
  int boilerNumber;   // номер энергоблока, в который нужно топливо отправить
};

HANDLE BoilerProviderChan; // канал для инфомирования энергоблоками пункта заготовления топлива,
                            // о том, что какой-то энергоблок пуст
HANDLE ProviderTransporterChan; // канал для обмена информацией между пунктом заготовления топлива и транспортным средством
LongMsg m;

void A () // нить для транспортного средства
{
  int w, d; // w - объем топлива, d - задержка движения в зависимости от объема топлива
  unsigned long s, foo;
  int stat;

  HANDLE TransporterBoilerChan[4]; // 4 канала для обмена информацией между энергоблоками
                                     // и транспортным средством
  TransporterBoilerChan[0] = CreateNamedPipe ("\\\\.\\pipe\\TBChan",
    PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4, 4, 4, 0, 0);
  TransporterBoilerChan[1] = CreateNamedPipe ("\\\\.\\pipe\\TBChan",
    PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4, 4, 4, 0, 0);
  TransporterBoilerChan[2] = CreateNamedPipe ("\\\\.\\pipe\\TBChan",
    PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4, 4, 4, 0, 0);
  TransporterBoilerChan[3] = CreateNamedPipe ("\\\\.\\pipe\\TBChan",
    PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4, 4, 4, 0, 0);
  ConnectNamedPipe (TransporterBoilerChan[0], 0);
  ConnectNamedPipe (TransporterBoilerChan[1], 0);
  ConnectNamedPipe (TransporterBoilerChan[2], 0);
  ConnectNamedPipe (TransporterBoilerChan[3], 0);

  setfillstyle (1, cc);
  bar (480, 40, 499, 59);
  ReadFile (ProviderTransporterChan, &m, sizeof m, &s, 0); // ждем сообщение от пункта заготовления топлива
  for (int i = 480; i >= 60; i -= 10) // перемещаем транспортное средство к
  {                                   // пункту заготовления топлива
    setfillstyle (1, cc);
    bar (i, 40, i + 19, 59);
    delay (20);
    if (i > 60)            // в месте назначения не будем стирать рисунок
    {
      setfillstyle (1, cw);
      bar (i, 40, i + 19, 59);
    }
  }
  while (1)
  {
    // сообщаем пункту заготовления топлива о готовности и
    // ждем от пункта заготовления топлива подтверждения, что он загрузил
    // топливо в транспортное средство
    stat = TransactNamedPipe (ProviderTransporterChan, &foo, 4, &m, sizeof m, &foo, 0);
    if (stat == 0)
      break;
    w = m.w;
    int boilerNumber = m.boilerNumber;  // принимаем вес топлива и номер котла, в который
    d = w * 7;                        // нужно это топливо везти
    for (int i = 60; i <= 200 + 80 * boilerNumber; i += 10)
    {                           // везем топливо к котлу
      setfillstyle (1, ca);
      bar (i, 40, i + 19, 59);
      delay (d);
      if (i < 200 + 80 * boilerNumber)
      {
        setfillstyle (1, cw);
        bar (i, 40, i + 19, 59);
      }
    }

    // сообщаем котлу, что привезли топливо с весом w и ждем от него
    // подтверждения, что он забрал все топливо
    stat = TransactNamedPipe (TransporterBoilerChan[boilerNumber], &w, 4, &foo, 4, &foo, 0);
    if (stat == 0)
      break;

    for (int i = 200 + 80 * boilerNumber; i >= 60; i -= 10)
    {                        // перемещаем транспортное средство обратно
      setfillstyle (1, cc);      // к пункту заготовления топлива
      bar (i, 40, i + 19, 59);
      delay (20);
      if (i > 60)
      {
        setfillstyle (1, cw);
        bar (i, 40, i + 19, 59);
      }
    }
  }
  ExitProcess(0);
}

void C(int n) // нити для энергоблоков
{
  int w, x;
  x = 180 + n * 80;
  unsigned long s, foo;
  HANDLE TransporterBoilerChan; // канал для обмена информацией между транспортным средством
                                // и соответствующим энергоблоком
  TransporterBoilerChan = CreateFile ("\\\\.\\pipe\\TBChan",
    GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

  WriteFile (BoilerProviderChan, &n, 4, &s, 0); // сообщаем пункту заготовления топлива, что котел пуст
  if (s == 0)
    ExitProcess(0);
  while (1)
  {
    ReadFile (TransporterBoilerChan, &w, 4, &s, 0); // ждем сообщение от транспортного средства,
                                   // что оно привезло топливо и определяем его вес
    if (s == 0)
      break;
    for (int i = 0; i < w; i++) // заливаем топливо в энергоблок
    {
      setfillstyle (1, cb);
      bar (x, 85 + i * 20, x + 59, 85 + i * 20 + 19);
      delay (100);
    }
    WriteFile (TransporterBoilerChan, &foo, 4, &s, 0); // сообщаем транспортному средству,
    if (s == 0)                  // что залили из него все топливо
      break;
    for (int i = w - 1; i >= 0; i--)
    {                              // сжигаем топливо постепенно
      setfillstyle (1, cw);
      bar (x, 85 + i * 20, x + 59, 85 + i * 20 + 19);
      delay (2000);
    }
    WriteFile (BoilerProviderChan, &n, 4, &s, 0); // сообщаем пункту заготовления
    if (s == 0)            // топлива, что котел снова пуст
      break;
  }
  ExitProcess(0);
}

void mainx ()
{
  resize (520, 320);
  outtextxy(230, 10, "e-station");
  setcolor(cc);
  line(40, 70, 479, 70);
  setfillstyle (1, cc);
  for (int i = 0; i < 4; i++)
    bar(180 + i * 80, 80, 239 + i * 80, 83);

  BoilerProviderChan = CreateNamedPipe ("\\\\.\\pipe\\BPChan", PIPE_ACCESS_OUTBOUND,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 4, 4, 0, 0);
  ProviderTransporterChan = CreateNamedPipe ("\\\\.\\pipe\\PTChan", PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 4, sizeof m, 0, 0);
  ConnectNamedPipe (BoilerProviderChan, 0);
  ConnectNamedPipe (ProviderTransporterChan, 0);

  // создаем все нити
  CreateThread (0, 0, (LPTHREAD_START_ROUTINE) A, 0, 0, 0);
  CreateThread (0, 0, (LPTHREAD_START_ROUTINE) C, (LPVOID) 0, 0, 0);
  CreateThread (0, 0, (LPTHREAD_START_ROUTINE) C, (LPVOID) 1, 0, 0);
  CreateThread (0, 0, (LPTHREAD_START_ROUTINE) C, (LPVOID) 2, 0, 0);
  CreateThread (0, 0, (LPTHREAD_START_ROUTINE) C, (LPVOID) 3, 0, 0);
}
