import processing.net.*; //ネットワークライブラリの使用宣言
import processing.serial.*;
import processing.video.*; // 動画ライブラリの使用宣言
import gab.opencv.*;

Serial Myport;

int numRecvByte = 0;

int [] ADIntVal = new int [2];
float [] ADRealVal = new float[2];

byte [] RecvByteBuff = new byte[256];

Client   myClient; //クライアントクラスclientの宣言

float  SendData; //送信するfloat型の変数

float val0 = 0;//増加検知用の変数

int state1 = 0;//状態

String[] FileName = new String[4]; // 画像ファイル名を格納する文字列配列

String[] Message = new String[2];  // メッセージ用文字列

String Time;

PImage[] img = new PImage[4]; // イメージ型配列imgを宣言

Capture video; // Captureオブジェクトの宣言

OpenCV opencv;

int numImg = 0; // 送信する画像のインデックス

int state = 0;

//******************************************************************************
// 初期設定関数
//******************************************************************************
void setup( ){
  
  size( 1000, 700 ); // ウィンドウを生成
  
  // 日本語フォント(BIZ UDゴシック)で、サイズ16のフォントを生成
  PFont font = createFont("BIZ UDゴシック", 16, true);
  textFont(font); // 生成したフォントを設定

  // サーバーに接続(localhostは自パソコン)
  myClient = new Client( this, "localhost", 5554 ); 
    
  SendData = 0.0f; // 初期値
  
  int i;
  for (i = 0; i < Serial.list().length; i++){
    println(Serial.list()[i]);
  }
  println("ARE available");
  
  Myport = new Serial(this, Serial.list()[i-1], 115200);
  
  // カメラの設定(デバイス番号0、解像度640x480)
  video = new Capture(this, 640,480);
  opencv = new OpenCV(this, 640,480);
  video.start();
  
  Message[0] = Message[1] = " "; // メッセージの初期値
}

PImage binImg;

void draw( ) //画面描画(100ms毎に起動)
{
  background(#2D3986); //青に塗りつぶす.
  Myport.write(0);
  
  String[] cameras = Capture.list();
  while( cameras.length == 0){
    cameras = Capture.list();
  }
  
  
  //左上にクライアントと自分のIPアドレスを表示
  text( "クライアント: " + myClient.ip(), 30, 20 );
  
  //送信データを表示
  text("電圧値 =" + nf(ADRealVal[0],1, 2) + "[V]",30,40);
  
  Time = year() + "年" + month() + "月" + day() + "日" + hour() + ":" + minute() + ":" + second();
  
  text(Time,10,60);
  
  if(video != null){
    set(10,130,video);
    opencv.loadImage(video);
   
  }
}

void captureEvent(Capture camera){
  camera.read();
}

void serialEvent (Serial RecvPort){
  
  
  
  String SendDataString;
  
  RecvByteBuff[numRecvByte] = (byte) RecvPort.read();
  numRecvByte++;
  
  if(numRecvByte == 4){
    
    ADIntVal[0] = RecvByteBuff[1] << 8 |(RecvByteBuff[0] & 0xff);
   
    ADRealVal[0] = ((ADIntVal[0] / 1023.0) * 5.0);
    
    numRecvByte = 0;
      
  //float型を文字列に変換
  
  if(ADRealVal[0] - val0 > 0.2){
    
    //重さが増えたら
    SendDataString = str(ADRealVal[0]);
    val0 = ADRealVal[0];
    state1 = 1;
    delay(200);
 
    //サーバに文字列を送信
    //myClient.write(SendDataString);
    
  }
 
  if(ADRealVal[0]  == 0.0 && state1 == 1){
    val0 = 0;
    SendDataString = str(ADRealVal[0]);
    state1 = 0;
    delay(200);
    
    //myClient.write(SendDataString);

    
    String savedFileName = "Image.jpg";
    video.save(savedFileName); // カメラのフレームを保存
    
    // 保存した画像を読み込み配列に格納
    img[numImg] = loadImage(savedFileName);
  if (img[numImg] == null) {
    println("画像の読み込みに失敗しました: " + savedFileName);
  } else {
    println("画像が正常に読み込まれました: " + savedFileName);
    Message[1] = "写真を撮影し保存し、送信準備完了: " + savedFileName;
}
  }   
  }
}

// データを受信したら起動される関数(引数は送信先の情報)
int ImgHeight = 0;
int ImgWidth = 0;
byte[] SendImgData;

void clientEvent(Client c) { 
  int NumBytes = 0;
  
  switch (state) {
    case 0: // 画像の高さと幅の送信
      NumBytes = c.available();
      if (NumBytes >= 1) {
        c.clear(); // 受信バッファを空にする。
        
        // 画像の高さと幅を送信(それぞれint型4バイト)
        ImgHeight = img[numImg].height;
        ImgWidth = img[numImg].width;
        byte[] SendHW = new byte[8]; // 送信用バッファ
        
        // 画像の高さを送信バッファに詰める。
        SendHW[0] = (byte) ImgHeight;
        SendHW[1] = (byte)(ImgHeight >> 8);
        SendHW[2] = (byte)(ImgHeight >> 16);
        SendHW[3] = (byte)(ImgHeight >> 24); 
        // 画像の幅を送信バッファに詰める。
        SendHW[4] = (byte) ImgWidth;
        SendHW[5] = (byte)(ImgWidth >> 8);
        SendHW[6] = (byte)(ImgWidth >> 16);
        SendHW[7] = (byte)(ImgWidth >> 24);
        
        myClient.write(SendHW); // バッファをサーバに送信
        state = 1; // 状態遷移
        println("画像のサイズを送信しました");
      }
      break;
    
    case 1: // 画像データの送信
      NumBytes = c.available();
      if (NumBytes >= 1) {
        c.clear(); // 受信バッファを空にする。
        
        // 送信バッファの動的確保(総画素数×RGBの3バイト分)
        SendImgData = new byte[ImgWidth * ImgHeight * 3];
        int idx = 0;
        // 画像データを全部、送信バッファに詰め込む。
        for (int i = 0; i < ImgWidth * ImgHeight; i++) {
          color pix = img[numImg].pixels[i]; // 画像データから1画素を取り出す。
          SendImgData[idx + 0] = (byte) red(pix); // 画素の赤成分を送信バッファに詰める。
          SendImgData[idx + 1] = (byte) green(pix); // 画素の緑成分を送信バッファに詰める。
          SendImgData[idx + 2] = (byte) blue(pix); // 画素の青成分を送信バッファに詰める。
          idx += 3;  
        }
        myClient.write(SendImgData); // 送信バッファをサーバに送信
        state = 2; // 状態遷移
        println("画像データを送信しました");
      }
      break;
      
    case 2: // サーバーから画像データの受信完了が来るまで待つ
      NumBytes = c.available();
      println(NumBytes);
      if (NumBytes >= 1) {
        c.clear(); // 受信バッファを空にする。
        Message[1] = FileName[numImg] + " : 画像送信の完了 " + SendImgData.length + "[バイト]";
        state = 0;
      }
      break;
  }
}