#include "EquipmentAccessPort.h"
#include <iostream>

#include "Helper/Singleton.h"
#include "Logger/Logger.h"
#include "Helper/Decoders.h"
#include "UpperTestAdapter.h"
#include "Ports/MessagesIdentifiers.h"

using namespace std;
using namespace t3devlib;
using namespace UpperTestAdapter;

EquipmentAccessPort::EquipmentAccessPort (PortId& portId) : Port (portId)
{
  stringstream ss;
  ss << "EquipmentAccessPort ctor()" << portId;
  Logger::Instance().LogDebug(ss.str());
}

EquipmentAccessPort::~EquipmentAccessPort()
{
  Logger::Instance().LogDebug("EquipmentAccessPort dtor() not implemented");
}

bool EquipmentAccessPort::Map (const PortId& connected_port_id)
{
  stringstream ss;
  ss << "EquipmentAccessPort::Map(): " << connected_port_id << " - " << connected_port_id.GetComponentId();
  Logger::Instance().LogDebug(ss.str());

  Singleton<UpperTestAdapter::UpperTestAdapter>::Instance().RegisterEquipmentAccessPort((PortId *)&connected_port_id, &connected_port_id.GetComponentId());
  
  return true; 
} 
 
bool EquipmentAccessPort::Unmap (const PortId& connected_port_id)
{ 
  //TODO: unregister filter; remove from m_connectedPorts
  Logger::Instance().LogError("EquipmentAccessPort::Unmap() not implemented");
  return true; 
}

bool EquipmentAccessPort::Send (const ComponentId& from,const Bitstring& msg)
{
  stringstream ss;
  ss << "EquipmentAccessPort Send: " << from;
  Logger::Instance().LogInfo(ss.str());

  unsigned char processDone = 0x00; // Processing result code - Set to 0 on success, set to 2 otherwise.

  // Retrieve and convert parameters.
  ss.str("");
  ss << "##### bsMsg(HEXA value): " << msg.GetValueHexa();
  Logger::Instance().LogInfo(ss.str());
  int length;
  string frame = msg.GetValueHexa();
  int offset = 0;
  
  int messageType = static_cast<int>(Decoders::Instance().DecodeByte(frame, &offset));
  ss.str("");
  ss << "EquipmentAccessPort::Send: messageType=" << messageType << " - " << offset;
  Logger::Instance().LogDebug(ss.str());
  // Trigger command.
  string trigger = Decoders::Instance().DecodeLengthPlusString(frame, &offset, &length);
  ss.str("");
  ss << "EquipmentAccessPort::Send: trigger=" << trigger << " - " << offset  << " - " << length;
  Logger::Instance().LogDebug(ss.str());
  
  // Number of items in the parameters list.
  short paramsNum = Decoders::Instance().DecodeParamsNum(frame, &offset);
  ss.str("");
  ss << "EquipmentAccessPort::Send: paramsNum=" << paramsNum << " - " << offset  << " - " << length;
  Logger::Instance().LogDebug(ss.str());
  
  // Extract parameters.
  std::vector<string> parameterList;
  for (short counter = 0; counter < paramsNum; counter++)
  {
    parameterList.push_back(Decoders::Instance().DecodeLengthPlusString(frame, &offset, &length));
    ss.str("");
    ss << "EquipmentAccessPort::Send: parameter added: " << parameterList[parameterList.size() - 1] << " - " << offset << " - " << length;
    Logger::Instance().LogDebug(ss.str());
  }
  
  int result = Singleton<UpperTestAdapter::UpperTestAdapter>::Instance().ProcessTriggerCommand(from, trigger, parameterList);
  
  // Prepare the response.
  Bitstring buffer;
  // Get message index
  unsigned char idx = MessagesIdentifiers::GetIdx(MessagesIdentifiers::EquipmentOperationRsp);
  if (idx == 0xff) {
    std::string errmsg ("unsupported response message value EquipmentOperationRsp'\n");
    throw errmsg;
    Logger::Instance().LogError(errmsg);
  }
  // Set message index
  Unsigned fieldLength(8); // 1 octet length
  fieldLength.SetValue(idx);
  buffer.Append(fieldLength);
  //Set status
  Unsigned responseBuffer(8, result);
  buffer.Append(responseBuffer);
  // Set reason
  Unsigned reasonLength(2 * 8, 0); // omitted
  buffer.Append(reasonLength);
  // Send the response.
  ss.str("");
  ss << "EquipmentAccessPort::Send: buffer=" << buffer;
  Logger::Instance().LogDebug(ss.str());
  PortId *port = Singleton<UpperTestAdapter::UpperTestAdapter>::Instance().GetEquipmentAccessPortIdFromComponent(from);
  ss.str("");
  ss << "EquipmentAccessPort::Send: Send response to " << port << " - " << *port;
  Logger::Instance().LogInfo(ss.str());
  clog << "EquipmentAccessPort::Send: Call EnqueueMsg" << std::endl;
  EnqueueMsg (*port, buffer);
  
  return true;
}

void EquipmentAccessPort::ProcessTriggerCommandsComplete(const ComponentId &to)
{
  //std::cerr << "EquipmentAccessPort::ProcessTriggerCommandsComplete() not implemented" << std::endl;
}

