/*!
* This method transmits binary data over an open TCP or UDP connection.
* @param data The data to transmit.
* @param waitForResponse Expect/wait for a reply from the server, default = true.
* @return `true` if the data was successfully transmitted,
* otherwise `false`.
*/
bool Sodaq_WifiBee::transmitBinaryData(const uint8_t* data, const size_t length, const bool waitForResponse)
{
  createSendBuffer();
  sendEscapedBinary(data, length);
  transmitSendBuffer();

  bool result;
  result = skipTillPrompt(SENT_PROMPT, RESPONSE_TIMEOUT);

  if (result && waitForResponse) {
    if (skipTillPrompt(RECEIVED_PROMPT, SERVER_RESPONSE_TIMEOUT)) {
      readServerResponse();
    }
    else {
      clearBuffer();
    }
  }

  return result;
}
/*!
* This method transmits ASCII data over an open TCP or UDP connection.
* @param data The data to transmit.
* @param waitForResponse Expect/wait for a reply from the server, default = true.
* @return `true` if the data was successfully transmitted,
* otherwise `false`.
*/
bool Sodaq_WifiBee::transmitAsciiData(const char* data, const bool waitForResponse)
{
  createSendBuffer();
  sendEscapedAscii(data);
  transmitSendBuffer();

  bool result;
  result = skipTillPrompt(SENT_PROMPT, RESPONSE_TIMEOUT);

  if (result && waitForResponse) {
    if (skipTillPrompt(RECEIVED_PROMPT, SERVER_RESPONSE_TIMEOUT)) {
      readServerResponse();
    }
    else {
      clearBuffer();
    }
  }

  return result;
}
/*!
* This method constructs and sends a generic HTTP request.
* @param server The server/host to connect to (IP address or domain).
* @param port The port to connect to.
* @param The HTTP method to use. e.g. "GET", "POST" etc.
* @param location The resource location on the server/host.
* @param headers Any additional headers, each must be followed by a CRLF.
* HOST & Content-Length headers are added automatically.
* @param body The body (can be blank) to send with the request. Must not start with a CRLF.
* @param httpCode The HTTP response code is written to this parameter (if a response is received).
* @return `true` if a connection is established and the data is sent, `false` otherwise.
*/
bool Sodaq_WifiBee::HTTPAction(const char* server, const uint16_t port,
  const char* method, const char* location, const char* headers,
  const char* body, uint16_t& httpCode)
{
  bool result;

  // Open the connection
  result = openConnection(server, port, "net.TCP");

  if (result) {
    createSendBuffer();

    sendAscii(method);
    sendAscii(" ");
    sendAscii(location);
    sendAscii(" HTTP/1.1\\r\\n");

    sendAscii("HOST: ");
    sendAscii(server);
    sendAscii(":");

    char buff[11];
    itoa(port, buff, 10);
    sendAscii(buff);
    sendAscii("\\r\\n");

    if (strcmp(method, "GET") != 0) {
      sendAscii("Content-Length: ");
      itoa(strlen(body), buff, 10);
      sendAscii(buff);
      sendAscii("\\r\\n");
    }

    sendEscapedAscii(headers);
    sendAscii("\\r\\n");

    sendEscapedAscii(body);

    transmitSendBuffer();

    // Wait till we hear that it was sent
    result = skipTillPrompt(SENT_PROMPT, RESPONSE_TIMEOUT);

    // Wait till we get the data received prompt
    if (result) {
      if (skipTillPrompt(RECEIVED_PROMPT, SERVER_RESPONSE_TIMEOUT)) {
        while (skipTillPrompt(RECEIVED_PROMPT, NEXT_PACKET_TIMEOUT)) {
        }

        readServerResponse();
        parseHTTPResponse(httpCode);
      }
      else {
        clearBuffer();
      }
    }

    // The connection might have closed automatically
    closeConnection();
  }

  return result;
}
void loop()
{
	if (timing) {
		timerTime += millis() - lastTime;
		lastTime = millis();
	}

	if (state == WAITING || state == TIMER_COUNTDOWN) {
		if (state == WAITING && timing) disableTiming();
		if (readRFID()) {
			//Serial.print("RFID: ");
			//Serial.println(rfidNum);

			convertRFID();
			if (serverRequest()) {
				state = SERVER_WAIT;
				enableTiming();
			}
			else state = WAITING;
		}
	}
	else if (state == SERVER_WAIT){
		//Serial.println(timerTime);
		if (timerTime < TIMEOUT) {
			if (readServerResponse()) {
				disableTiming();
				parseResponse();
				if (authorized) {
					state = TIMER_COUNTDOWN;
					turnOn();
				}
				else state = DENIED;
			}
		}
		else {
			state = WAITING;
		}
	}
	else if (state == DENIED) {
		Serial.println("DENIED");
		state = WAITING;
	}

	if (state == TIMER_COUNTDOWN && timing && currentOn()) {
		disableTiming();
	}
	else if (state == TIMER_COUNTDOWN && (!timing && !currentOn())) {
		enableTiming();
	}

	if (state == TIMER_COUNTDOWN) {
		if ((timing && (timerTime > authorizedTime)) || checkButton()) {
			state = WAITING;
			disableTiming();
			turnOff();
		}
	}

	/*if (timerTime > 0)
		Serial.println(timerTime);*/
}
///
/// \brief Client::Client
/// \param parent
/// constructor for the Client class
Client::Client(QWidget *parent)
:   QDialog(parent), networkSession(0)
{
    // Setting up widgets for the login window
    // set labels
    m_userLabel = new QLabel(tr("Email: "));
    m_passwordLabel = new QLabel(tr("Password: "******"IP: "));
    m_portLabel = new QLabel(tr("Port: "));
    m_loginStatusLabel = new QLabel(tr("Please fill in IP and port and press Connect."));

    // setup edits
    m_hostEdit = new QLineEdit;
    m_portEdit = new QLineEdit;
    m_portEdit->setValidator(new QIntValidator(1, 65535, this));
    m_userEdit = new QLineEdit;
    m_passwordEdit = new QLineEdit;

    // connect labels to edits
    m_userLabel->setBuddy(m_userEdit);
    m_passwordLabel->setBuddy(m_passwordEdit);
    m_hostLabel->setBuddy(m_hostEdit);
    m_portLabel->setBuddy(m_portEdit);

    // setup buttons
    m_registerBtn = new QPushButton(tr("Register"));
    m_loginBtn = new QPushButton(tr("Log in"));
    m_connectBtn = new QPushButton(tr("Connect"));

    // initial button settings
    m_connectBtn->setDefault(true);
    //m_loginBtn->setEnabled(false);
    m_registerBtn->setEnabled(false);

    // button box
    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(m_connectBtn, QDialogButtonBox::ActionRole);
    buttonBox->addButton(m_registerBtn, QDialogButtonBox::ActionRole);
    buttonBox->addButton(m_loginBtn, QDialogButtonBox::ActionRole);

    // connect button press signals to slots
    connect(m_connectBtn, SIGNAL(clicked()), this, SLOT(startConnection()));
    connect(m_registerBtn, SIGNAL(clicked()), this, SLOT(registerUser()));
    connect(m_loginBtn, SIGNAL(clicked()), this, SLOT(login()));

    // read from server when server sends data
    m_tcpSocket = new QTcpSocket(this);
    connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(readServerResponse()));
    connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                this, SLOT(displayError(QAbstractSocket::SocketError)));

    // put widgets on a window
    //QGridLayout *loginLayout = new QGridLayout;

    loginLayout.addWidget(m_hostLabel, 0, 0);
    loginLayout.addWidget(m_hostEdit, 0, 1);
    loginLayout.addWidget(m_portLabel, 1, 0);
    loginLayout.addWidget(m_portEdit, 1, 1);
    loginLayout.addWidget(m_userLabel, 2, 0);
    loginLayout.addWidget(m_userEdit, 2, 1);
    loginLayout.addWidget(m_passwordLabel, 3, 0);
    loginLayout.addWidget(m_passwordEdit, 3, 1);
    loginLayout.addWidget(m_loginStatusLabel, 4, 0, 1, 2);
    loginLayout.addWidget(buttonBox, 5, 0, 1, 2);
    setLayout(&loginLayout);

    // set up the inbox
    m_inbox = new QListWidget();
    QObject::connect(m_inbox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(viewMessage(QListWidgetItem*)));
    m_inbox->setStyleSheet("QListWidget::item{border-bottom:1px solid black;}");

    m_viewingSent = 0;

    // test code for setting up emails
    Email* e1 = new Email();
    e1->setFrom("John");
    e1->setSubject("money");
    e1->setMessage("Yo n***a, you betta give me my money!");
    e1->setRead(false);
    e1->setText(e1->getFrom() + " | " + e1->getSubject());
    e1->setData(12, 1);
    e1->setID(1);
    Email* e2 = new Email();
    e2->setFrom("Simon");
    e2->setSubject("hangout");
    e2->setMessage("Hey man, do you want to hangout?");
    e2->setRead(false);
    e2->setText(e2->getFrom() + " | " + e2->getSubject());
    m_emails.append(e1);
    m_emails.append(e2);
    e2->setData(12, 2);
    e2->setID(2);

}