
#include <iostream>
#include <math.h>
#include <fstream>
#include <string>
#include <iomanip>
#include <sstream>
#include <unistd.h>


#include <Base/GCString.h>
#include <pylon/PylonIncludes.h>
#include <pylon/Platform.h>
#include <pylon/PylonLinkage.h>
#include <pylon/ImagePersistence.h>

#include <wiringPi.h>
#include <pylon/DeviceInfo.h>
#include <pylon/gige/BaslerGigEInstantCamera.h>
#include <pylon/gige/BaslerGigEGrabResultPtr.h>

#include <pylon/gige/BaslerGigEInstantCamera.h>

#define motor   1
#define trig    4

#define red     21
#define green   22
#define blue    23

#define svit    HIGH
#define nesvit  LOW


int HeightOfImage = 734; // Pocet radku grabovaneho snimku


typedef Pylon::CBaslerGigEInstantCamera Camera_t;
typedef Pylon::CBaslerGigEGrabResultPtr Ptr_t;

using namespace Basler_GigECameraParams;
using namespace Pylon;
using namespace GenApi;
// Namespace for using cout.
using namespace std;

static const uint32_t c_countOfImagesToGrab = 1;




int main(int argc, char* argv[])
{
    int exitCode = 0;
    
    if(wiringPiSetup() == -1)
		std::cout<<"Chyba wiringu";

    // Nastaveni pinu pro ovladani prislusnych prvku jako Vystupni
    pinMode(motor,OUTPUT);
    pinMode(red, OUTPUT);
    pinMode(blue, OUTPUT);
    pinMode(green, OUTPUT);
    pinMode(trig, OUTPUT);

    // Inicializace Pylon runtimu
    PylonInitialize();
    
    try
    {
        // Vytvoreni objektu instant camera, pridano je zarizeni ktere je prvni nalezeno
        Camera_t camera( CTlFactory::GetInstance().CreateFirstDevice());

        camera.MaxNumBuffer = 5;

        Ptr_t ptrGrabResult;
        
        
        
        INodeMap& nodemap = camera.GetNodeMap();
        
        camera.Open();      //MEGA DULEZITE PRED CTENIM A ZAPISOVANIM PARAMETRU, jinak nefunguje zapisovani parametru do kamery :-)
        camera.BinningHorizontal.SetValue(3);   // Slucovani tri sousednich pixelu do jednoho
        camera.Height.SetValue(HeightOfImage*3); // Nastaveni poctu radku ramce
        
        
        // Nastaveni Zesileni a sirky
        CIntegerParameter(nodemap, "GainRaw").SetValue(1100);
        CIntegerParameter(nodemap, "Width").SetValue(786);
        
        
        //FUNGUJE POUZE PRO GIGE CAMERA
        // Nastaveni parametru spousteni expozice
        camera.TriggerSelector.SetValue(TriggerSelector_LineStart);         
        camera.TriggerMode.SetValue(TriggerMode_On);
        camera.TriggerSource.SetValue(TriggerSource_Line1);
        camera.TriggerActivation.SetValue(TriggerActivation_RisingEdge);
        
        camera.ExposureMode.SetValue(ExposureMode_Timed);
        camera.ExposureTimeAbs.SetValue(110.0);
        
        CIntegerParameter gain(nodemap, "GainRaw");
        
        // Zacatek grabovani
        camera.StartGrabbing( c_countOfImagesToGrab);
        int cislo = 0;
        
        digitalWrite(motor,HIGH);   // Sepnuti motoru
        delayMicroseconds(200000);  // Doba na rozjezd motoru na konstantni otacky
        digitalWrite(red,nesvit);   // Zadne z led kanalu nesviti
        digitalWrite(green,nesvit);
        digitalWrite(blue,nesvit);

        
        
        int frek = 1500; // vzorkovaci frekvence jednoho kanalu cca 500 Hz
        int perioda = 0;
        perioda = 1000000/frek;
        
        // Proces expozice jednotlivych radku
        for (int i = 0;i<camera.Height.GetValue();++i)
        {
                
                switch(i%3)
                {
                        case 0:                             // Stridani kanalu osvetleni, vzdy sviti jeden
                                digitalWrite(red,svit);
                                digitalWrite(green,nesvit);
                                digitalWrite(blue,nesvit);
                                break;
                        case 1:
                                digitalWrite(green,svit);
                                digitalWrite(red,nesvit);
                                digitalWrite(blue,nesvit);
                                break;
                        default:
                                digitalWrite(blue,svit);
                                digitalWrite(red,nesvit);
                                digitalWrite(green,nesvit);
                                break;
                 }
                 
                 
                 delayMicroseconds(50); //KVULI MOZNEMU ZPOZDENI OSVETLENI, NAPR. PARAZITNI KAPACITY U LEDEK
                         
        digitalWrite(trig,HIGH);    // Spusteni expozice kamery hardwarovym triggerem - zacatek pulsu
		
		delayMicroseconds(5);
        
        
        digitalWrite(trig,HIGH);    // pro jistotu jeste jednou - nema vetsi vliv
		
        delayMicroseconds(10);
        

		digitalWrite(trig,LOW);     // sestupna hrana pulsu

		
		delayMicroseconds(perioda-160); // cekaci doba
        
                cislo++;
        }
        
        
        
        
        
        camera.RetrieveResult( 5000, ptrGrabResult, TimeoutHandling_ThrowException); // grabovani

        digitalWrite(red,nesvit); // zhasnuti vsech svetel, zastaveni motoru
        digitalWrite(green,nesvit);
        digitalWrite(blue,nesvit);
        digitalWrite(motor,LOW);
        
        // Uspesne grabovan? Uloz ho.
        if (ptrGrabResult->GrabSucceeded())
        {
            
            const uint8_t *pImageBuffer = (uint8_t *) ptrGrabResult->GetBuffer();
  
            //UKLADANI OBRAZKU
            cout << "Acquisition Done."<<endl;
            
            String_t nazev;
            
            //Zde moznost nastavit nazev se zvysujicim se indexem, anebo stejny nazev a snimky se budou prepisovat
            //Toto druhe reseni je vhodne pro praci s gui a je tu implicitne zvoleno

            int stejny_nazev = 1;

            if (stejny_nazev != 1)
            {
                    
                
                //String_t retezec;
                string str1 = "vystup_";
                string strpocitadlo;
                
                //NACITANI ZE SOUBORU
                int pocitadlo;
                ifstream isnimek;
                isnimek.open("index.txt");
                if (isnimek.fail())
                {
                        cout<<"Nelze otevrit"<<endl;
                        return 1;
                }
                isnimek >> pocitadlo;
                isnimek.close();
                //cout<<"Pocitadlo ma index: "<<pocitadlo <<endl;
                
                // PRACE S HODNOTAMI
                stringstream ss;
                ss<<setfill('0')<<setw(4)<<pocitadlo;
                strpocitadlo = ss.str();
                //strpocitadlo = to_string();
                strpocitadlo = str1+strpocitadlo+".png";
                //cout<<strpocitadlo<<endl;
                
                pocitadlo++;
                
                // ZAPIS DO SOUBORU	
                ofstream osnimek;
                osnimek.open("index.txt");
                if(osnimek.fail())
                {
                        cout << "Nelze otevrit zapisovaci soubor"<<endl;
                        return 1;
                }
                osnimek << pocitadlo;
                osnimek.close();
                
                nazev = String_t(strpocitadlo.c_str());

            }
            else
            {

                nazev = String_t("rawsnimek.png");
                
            }

            //String_t nazev = String_t(strpocitadlo.c_str());            
            CImagePersistence::Save( ImageFileFormat_Png, nazev, ptrGrabResult);
            
        }
        else
        {
            cout << "Error: " << ptrGrabResult->GetErrorCode() << " " << ptrGrabResult->GetErrorDescription() << endl;
        } 
        
       
    }
    catch (const GenericException &e)
    {
        // Error handling.
        cerr << "An exception occurred." << endl
        << e.GetDescription() << endl;
        exitCode = 1;
    }

    
    PylonTerminate();  

    return exitCode;
    
}
