package pro.arduino.adksensornetwork;
// część 1

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
import android.graphics.Color;
import android.widget.LinearLayout;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;

import com.android.future.usb.*;


import android.os.Handler; // drugi przykład
import android.os.Message;
// komponenty interfejsu użytkownika 
import android.view.View;
import android.widget.Button;
import android.widget.EditText;


public class SensorNetworkActivity extends Activity implements Runnable {
	  // deklaracje wejście i wyjścia ADK
	   UsbAccessory ARDUINO_ADK; // obiekt Accesory
	   ParcelFileDescriptor ADKstreamObj;
	   FileInputStream ReciveFromADK;
	   FileOutputStream SendtoADK;
	   // konfiguracja logowania
	   private static final String ACTION_USB_PERMISSION = "MEGA_ADK.USB_PERMISSION";
	   private static final String TAG = "MEGA ADK"; // logowanie wysłanego tagu debugującego
	   private UsbManager UsbManagerOBJ;
	   private PendingIntent Needed_Permission;
	   private boolean IsPermissionNeeded;
		 
	   // zmienne wykresu
	   private XYMultipleSeriesDataset SensorData = new XYMultipleSeriesDataset();
	   // zmienna XYMultipleSeriesRenderer zajmuje dwa wiersze w książce
	   private XYMultipleSeriesRenderer SensorRenderer = new XYMultipleSeriesRenderer();
	   private XYSeries Sensor1CurrentSeries = new XYSeries("Czujnik 1");
	   private XYSeries Sensor2CurrentSeries = new XYSeries("Czujnik 2");
	   private XYSeries Sensor3CurrentSeries = new XYSeries("Czujnik 3");	 
	   private GraphicalView SensorChartView;
	   // kontener wykresu i inne obiekty interfejsu graficznego
	   private LinearLayout layout;
	   private Button buttonSync;
	   private Button ScreenClear;
	   private EditText DataFromArduino;
	   // zmienne określające wygląd wykresu
	   double[] limits = new double[] {0, 500000,-127,127}; // granice wykresu
	   double x = 0; 
	   double y = 0; 
	   double xCount = 0;
	   double lastMinX = 0;
	   boolean Sync = false;;
	   
	   
	   
	// część 3
	@Override
	public void onCreate(Bundle savedInstanceState) {
	   super.onCreate(savedInstanceState);
	   setupAccessory();
	   setContentView(R.layout.main);
	   registerUIobjects();
		
	}// koniec onCreate	
	@Override
	public void onDestroy() {
	   unregisterReceiver(ADKReceiver);
	   super.onDestroy();
	}// koniec onDestroy

	@Override
	public void onPause() {
	   super.onPause();
	   closeAccessory();
	} // koniec onPause() 

	@Override
	public void onResume() {
	   super.onResume();
	   SetupGraph();
	    if (ReciveFromADK != null && SendtoADK != null) {
	      return;
	     } // koniec if (ReciveFromADK != ...
	   UsbAccessory[] accessories = UsbManagerOBJ.getAccessoryList();
	   UsbAccessory accessory = (accessories == null ? null : accessories[0]);
	    if (accessory != null) {
	     if (UsbManagerOBJ.hasPermission(accessory)) {
	       openAccessory(accessory);
	     } // koniec if (UsbManagerOBJ.hasPermission(accessory))
	     else {
	      synchronized (ADKReceiver) {
	       if (IsPermissionNeeded == true) {
	         UsbManagerOBJ.requestPermission(accessory, Needed_Permission);
	         IsPermissionNeeded = false;
	       } // koniec if (IsPermissionNeeded == true) 
	      } // koniec synchronized ADKReceiverr)
	     } // koniec else dla if (UsbManagerOBJ...
	     
	    }// koniec if (accessory != null)
	    else {
	      Log.d(TAG, "Zmienna mAccessory jest pusta");		
	    } // koniec else if (accessory != null)
	} // koniec onResume()

	// część 4
	private BroadcastReceiver ADKReceiver = new BroadcastReceiver() {
	 @Override
	 public void onReceive(Context context, Intent intent) {
	    String action = intent.getAction();
	     if (ACTION_USB_PERMISSION.equals(action) == true) {
	       synchronized (this) {
	        UsbAccessory accessory = UsbManager.getAccessory(intent);
	         if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
	           openAccessory(accessory);
	         }
	         else {
	           Log.d(TAG, "odmowa dostępu do akcesorium "+ accessory);
	         }
	        IsPermissionNeeded = true;
	       } // koniec synchronized (this)
	     }  // koniec if (ACTION_USB_PERMISSION.equals...
	     else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
	       UsbAccessory accessory = UsbManager.getAccessory(intent);
	        if (accessory != null && accessory.equals(ARDUINO_ADK)) {
	          closeAccessory();
	        }
	     } // koniec else if (UsbManager...
	 } // koniec void onReceive(Context contex ...
	}; // koniec private BroadcastReceiver..

	@Override
	public Object onRetainNonConfigurationInstance() {
	   if (ARDUINO_ADK != null) {
	     return ARDUINO_ADK;
	   }
	   else {
	      return super.onRetainNonConfigurationInstance();
	   }
	} // koniec public Object  onRetainNon*...

	// część 5
	private void openAccessory(UsbAccessory accessory) {
	   ADKstreamObj = UsbManagerOBJ.openAccessory(accessory);
	    if (ADKstreamObj != null) {
	      ARDUINO_ADK = accessory;
	      FileDescriptor fd = ADKstreamObj.getFileDescriptor();
	      ReciveFromADK = new FileInputStream(fd);
	      SendtoADK = new FileOutputStream(fd);
		 
	      // nowy kod
	      Thread ADKreadthread = new Thread(null, this, "ADK_Read_Thread");
	      ADKreadthread.start();
	      
		  Log.d(TAG, "akcesorium otwarte");
	    } // koniec if (ADKstreamObj
	    else {
	      Log.d(TAG, "błąd otwarcia akcesorium");
	    }
	} // koniec void openAccessory...

	private void setupAccessory() {
	   UsbManagerOBJ = UsbManager.getInstance(this);
	   Needed_Permission = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
	   IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
	   filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
	   registerReceiver(ADKReceiver, filter);
	    if (getLastNonConfigurationInstance() != null) {
	    	ARDUINO_ADK = (UsbAccessory) getLastNonConfigurationInstance();
	      openAccessory(ARDUINO_ADK);
	   }
	} // koniec private void setupAccessory() 

	private void closeAccessory() {
	   try {
	    if (ADKstreamObj != null) {
	      ADKstreamObj.close();
	    }
	   } // koniec try 
	   catch (IOException e) {
		   Log.e(TAG, "Wyjątek IO", e);
	   } 
	   finally {
	     ADKstreamObj = null;
	     ARDUINO_ADK = null;
	   } // koniec wszystkich try catch finally
	}// koniec private void closeAccessory()

	// część 6
	private void write(byte[] send){
	   if (SendtoADK != null) {
	      try {
	        SendtoADK.write(send);
	      }
	      catch (IOException e){ 
	        Log.e(TAG, "błąd zapisu", e);
	      }
	   }// koniec if (SendtoADK != null)	
	}// koniec private void write..

	// nowy kod

	public void run() {
	int RevivedBytes  = 0;
	  
	 while (true) { // ciagłe wywonywanie
		 byte[] buffer = new byte[80]; // maksymalna wielkość to 16384, ale spowalnia programn
	 try {
	     RevivedBytes = ReciveFromADK.read(buffer);
	  } 
	  catch (IOException e) {
	     Log.e(TAG, "Błąd odczytu", e);
	     break; 
	  }
	  if  (RevivedBytes >= 1 ) {
	     Message MakeBufferTransferable = Message.obtain(IncomingDataHandler);
	     MakeBufferTransferable.obj = new BufferData( buffer ,RevivedBytes);
	     IncomingDataHandler.sendMessage(MakeBufferTransferable);
	  }	
	 }// koniec while 
	}// koniec public void run()()
// część 7
	
	private void registerUIobjects(){
		  buttonSync = (Button) findViewById(R.id.syncbutton); 
		  ScreenClear = (Button) findViewById(R.id.clear);    
		  DataFromArduino = (EditText)findViewById(R.id.incomingData);	   
		  layout = (LinearLayout) findViewById(R.id.chart);
		  // poniższy wiersz zajmuje dwie linie w książce
		  SensorChartView = ChartFactory.getLineChartView(this, SensorData, 
		  SensorRenderer);
		  layout.addView(SensorChartView);
		} // koniec registerUIobjects
		// Funkcja określająca sposób rysowania wykresu
		public void SetupGraph(){	 
		   // ustawienie opcji wykresu
		   SensorRenderer.setAxisTitleTextSize(10);
		   SensorRenderer.setChartTitleTextSize(10);
		   SensorRenderer.setLabelsTextSize(10);
		   SensorRenderer.setLegendTextSize(10);
		   SensorRenderer.setMargins(new int[] {10, 10, 10, 0});
		   SensorRenderer.setAxesColor(Color.WHITE);
		   SensorRenderer.setShowGrid(true);
		   SensorRenderer.setYAxisMin(-127);
		   SensorRenderer.setYAxisMax(127);
		   SensorRenderer.setXAxisMin(0);
		   SensorRenderer.setXAxisMax(100);
		   SensorRenderer.setPanLimits(limits);
		   // dodanie trzech serii danych do zestawu 
		   SensorData.addSeries(Sensor1CurrentSeries);
		   SensorData.addSeries(Sensor2CurrentSeries);
		   SensorData.addSeries(Sensor3CurrentSeries);
		   // ustawienie kolorów krzywych zgodnie z biblioteką openFrameworks
		   XYSeriesRenderer Sensor1renderer = new XYSeriesRenderer();
		   Sensor1renderer.setColor(Color.GREEN);
		   XYSeriesRenderer Sensor2renderer = new XYSeriesRenderer();
		   Sensor2renderer.setColor(Color.YELLOW);
		   XYSeriesRenderer Sensor3renderer = new XYSeriesRenderer();
		   Sensor3renderer.setColor(Color.BLUE);
		   // dodanie do wykresu danych z czujników
		   SensorRenderer.addSeriesRenderer(Sensor1renderer);
		   SensorRenderer.addSeriesRenderer(Sensor2renderer);
		   SensorRenderer.addSeriesRenderer(Sensor3renderer);
		} // koniec SetupGraph
		// Funkcja obsługujące przychodzące dane  	
		Handler IncomingDataHandler = new Handler() {
		  @Override
		  public void handleMessage(Message msg) {
		    BufferData IncomingBuffer = (BufferData) msg.obj;
		    byte[] buffer = IncomingBuffer.getBuffer();
		    // pobranie danych z czujnika i dodanie do wykresu
		    byte sen1 = (byte) (buffer[5] - 127);
		    byte sen2 = (byte) (buffer[13] - 127);
		    byte sen3 = (byte) (buffer[21] - 127);
		    Sensor1CurrentSeries.add(xCount,  sen1 );
		    Sensor2CurrentSeries.add(xCount,  sen2 );
		    Sensor3CurrentSeries.add(xCount,  sen3 );
		    // sprawdzenie, czy potrzebne jest przesunięcie
		    refreshChart();
		    xCount++;
		    if (SensorChartView != null) {
		      SensorChartView.repaint();
		    }
		    // dodanie danych z bufora do pola tekstowego
		    String str = new String(buffer);
		    DataFromArduino.append(str);
		  }// koniec  handleMessage(Message msg)
		};// koniec  Handler IncomingDataHandler = new Handler()
		// sprawdzenie, czy potrzebne jest przesunięcie widoku wykresu
		private void refreshChart() {
		  // check if a shift of the graph view is needed 
		  if (xCount > SensorRenderer.getXAxisMax()) {
		    SensorRenderer.setXAxisMax(xCount);
		    SensorRenderer.setXAxisMin(++lastMinX);
		  }		    
		  SensorChartView.repaint();
		}
		// Zdarzenia Clear-Screen oraz Sync-Data generowane przez przyciski
		public void clearScreen (View v) {
		  byte[] BytestoSend = new byte[1];
		  BytestoSend[0] = 'b';
		  write(BytestoSend);
		  Sensor1CurrentSeries.clear();
		  Sensor2CurrentSeries.clear();
		  Sensor3CurrentSeries.clear();
		  xCount = 0 ;
		  lastMinX = 0 ; 
		  SensorRenderer.setYAxisMin(-127);
		  SensorRenderer.setYAxisMax(127);
		  SensorRenderer.setXAxisMin(0);
		  SensorRenderer.setXAxisMax(100);
		  Sync = false ;
		  SensorChartView.repaint();
		  DataFromArduino.setText(null);
		} // koniec clearScreen

		public void SyncData(View v) {
		  if (!Sync){
		    byte[] BytestoSend = new byte[1];
		    BytestoSend[0] = 'a';
		    write(BytestoSend); // wysłanie bufora do ADK
		    Sync = true;
		  }
		} // koniec void SyncData(View v)
}