void net_loop(){
  // main networking loop
  // this handles the user interface, but also repiles from couchdb

	switch(ui_state){
		case UI_READY:
			serve();
      handle_db_response();
			break;
		case UI_TWILOCK:
			// we do not process new socket inputs, as we have to wait for the twi bus to become ready:
			if(twi_try_lock_bus()){
				// we aquired the bus
				// now we have to do our access as fast as possible, as others might wait for bus access:
				// call command handler, who waits for access to the bus:
				twi_access_fun();
				
				fputs_P(PSTR("% "), &sock_stream);
				sock_stream_flush();
				// we again accept commands
				ui_state = UI_READY;
				twi_free_bus();
				int16_t b;
				while((b=fgetc(&sock_stream)) != EOF){
					if(b == '\n' || b == ';'){
						break;
					}
				}
				// handle other already existing commands in the buffer
				//ui_handleCMD(stream_get_sock());
			}
			break;
	}
}
void dataAvailable(struct dummy_packet * received, uint8_t src_addr){
	uint8_t i;
	for(i=0; i< MAX_SERVER_SOCK_NUM; i++){
		// TODO: check if socket is still connected.
		if (data_request[i]){
			stream_set_sock(i);
			fprintf(&sock_stream, "%u :: ", src_addr);
			send_result(received);
		}
	}
	sock_stream_flush();
}
void net_dataAvailable(struct dummy_packet * received, uint8_t src_addr){
  // This function is called, everytime, a set o measurement results from
  // one collector board was successfully received.

	uint8_t i;
  // make a backup of currently active socket
  // as we have to switch socket to db socket
  uint8_t currSock = stream_get_sock();
  // flush the active socket here?
  sock_stream_flush();

  //puts_P(PSTR("."));
  // send data to the database, if required:
  if(cfg.send_db){
    net_sendResultToDB(received, src_addr);
  //puts_P(PSTR(","));
  }

  // now send data to user intrefaces, if they requested so:
  for(i=0; i< MAX_SERVER_SOCK_NUM; i++){
    if (data_request[i]){
      if(W5100.readSnSR(i+FIRST_SERVER_SOCK) == SnSR::ESTABLISHED){
        stream_set_sock(i+FIRST_SERVER_SOCK);
        fprintf_P(&sock_stream, PSTR("\n%u :: "), src_addr);
        send_result(received);
        sock_stream_flush();
      }else{
        // if no the requesting client is already disconnected,
        // remove him from the request list:
        data_request[i] = 0;
      }
    }
  }
  //puts_P(PSTR("-"));
  // restore socket:
  stream_set_sock(currSock);
}
void handle_db_response(){
  // Couchdb will send responses after receiving json documents.
  // we have to receive these in order for the w5100 receive buffer
  // not to overflow.
  // Alternatively we can just clear the whole receive queue, as
  // receiving the whole data will take a lot of time
  //
  // here both approaches are implemented, as it might be useful to see
  // the database response for debugging. In this case, the response
  // can be redirected to the TCP user interface (redirect_flag)
  uint8_t b;
  uint8_t index;
  uint8_t content_flag = 0;
	uint8_t redirect_flag = 0;
	for(index = 0; index< MAX_SERVER_SOCK_NUM; index++){
		if(db_response_request[index]){
			redirect_flag = 1;
		}
	}

	if(redirect_flag == 0){
    // if no one wants to have the data, we can just clear the whole socket receive buffer.
		net_clear_rcv_buf(DB_CLIENT_SOCK);
	}else{
    // if at leat one wants to have the DB response redirected,
    // we receive byte by byte and forward them to the apropriate user interface:
    // Do not need to backup the current socket here, because it is not in serve function
		while(recv(DB_CLIENT_SOCK, &b, 1) > 0){
			content_flag = 1;
			for(index = 0; index< MAX_SERVER_SOCK_NUM; index++){
				if(db_response_request[index]){
					stream_set_sock(index+FIRST_SERVER_SOCK); 
					fputc(b, &sock_stream);
					sock_stream_flush();
				}
			}
		}
		if(!content_flag){
      // no data was available:
			return;
		}
	}
}
void ui_loop(){
	switch(ui_state){
		case UI_READY:
			serve();
			break;
		case UI_TWILOCK:
			// we do not process new socket inputs, as we have to wait for the twi bus to become ready:
			if(twi_try_lock_bus()){
				// we aquired the bus
				// now we have to do our access as fast as possible, as others might wait for bus access:
				// call command handler, who waits for access to the bus:
				twi_access_fun();
				sock_stream_flush();
				// we again accept commands
				ui_state = UI_READY;
				twi_free_bus();

				// handle other already existing commands in the buffer
				handleCMD(stream_get_sock());
			}
			break;
	}
}
void net_sendResultToDB(struct dummy_packet *packets, uint8_t board_addr){
  // Sends a set of 8 measurement results to the couchdb database

  int8_t sensor_index;
  int8_t comma_flag = 0;
  int16_t value;
  uint16_t len=0;
  PORTB &= ~(1<<PB1);
  PORTD &= ~(1<<PD5);
  if( W5100.readSnSR(DB_CLIENT_SOCK) != SnSR::ESTABLISHED ){
    if(!connect_db(cfg.port+1)){
      return;
    }
  }
  // Calculate length for the JSON header:
  for (sensor_index=0; sensor_index<8; sensor_index++){
    if(packets[sensor_index].header.error && packets[sensor_index].header.connected){
      // We do not send data, which might have an error
      continue;
    }
    if(packets[sensor_index].header.connected){
      switch(packets[sensor_index].header.type){
        case PACKET_TYPE_TSIC:
          len += JSON_TEMP_LEN;
          // length of "," or "}" at the end
          len++;
          break;
        case PACKET_TYPE_HYT:
          // There is no difference in temperature length
          // for HYT and TSIC.
          len += JSON_TEMP_LEN;
          len++;
          len += JSON_HUM_LEN;
          len++;
          break;
        default:
          break;
      }
    }
  }
  PORTB |= (1<<PB1);
  if(len==0){
    return;
  }
  len+=JSON_PREFIX_LEN;
  // length of "}" at the end
  len++;

  // Now we start sending data to couchdb
  stream_set_sock(DB_CLIENT_SOCK);
  net_sendHeadToDB(len);
#ifdef DEBUG
  printf_P(PSTR("Send Head \n\r"));
#endif

  /* convert packet data to json format
   * {"type":"value","data",{"bdddsdTEMP":"ddd.dd","bdddsdHUM":"ddd.dd"}}
   */
  fputs_P(PSTR(JSON_PREFIX), &sock_stream);
#ifdef DEBUG
  printf_P(PSTR("Send PREFIX \n\r"));
#endif
  comma_flag = 0;
  //puts_P(PSTR("+"));
  PORTB &= ~(1<<PB1);
  PORTD |= (1<<PD5);
  for (sensor_index=0;sensor_index<8;sensor_index++){
    if(packets[sensor_index].header.error && packets[sensor_index].header.connected){
      continue;
    }
    if(packets[sensor_index].header.connected){
      switch(packets[sensor_index].header.type){
        case PACKET_TYPE_TSIC:
          if(comma_flag){
            fputc(',', &sock_stream);
          }else{
            comma_flag = 1; 
          }
          value =  ((struct tsic_packet *)(packets))[sensor_index].temperature;
          fprintf_P(&sock_stream, PSTR(JSON_TEMP), JSON_OUTPUT);
#ifdef DEBUG
          printf_P(PSTR("Send temperature \n\r"));
#endif
          break;
        case PACKET_TYPE_HYT:
          if(comma_flag){
            fputc(',', &sock_stream);
          }else{
            comma_flag = 1; 
          }
          value = ((struct hyt_packet *)(packets))[sensor_index].temperature;
          fprintf_P(&sock_stream, PSTR(JSON_TEMP), JSON_OUTPUT);
          value = ((struct hyt_packet *)(packets) )[sensor_index].humidity;
          fputc(',', &sock_stream);
          fprintf_P(&sock_stream, PSTR(JSON_HUM), JSON_OUTPUT); 
          break;
        default:
          break;
      }
    }
  }
  fputc('}', &sock_stream);
  fputc('}', &sock_stream);
#ifdef DEBUG
  printf_P(PSTR("Send finished \n\r"));
#endif
  sock_stream_flush();
  PORTB |= (1<<PB1);
}