//*******************************************************************************
//* Copyright (c) 2008-2014 Synchrotron SOLEIL
//* All rights reserved. This program and the accompanying materials
//* are made available under the terms of the GNU Lesser Public License v3
//* which accompanies this distribution, and is available at
//* http://www.gnu.org/licenses/lgpl.html
//******************************************************************************
//******************************************************************************************
//
//
//			september 16, 2004 :  Source file of the WaveForm Class
//
//		it contains the waveform raw data, at least there will be scaled
//
//		author : X.Elattaoui
//
//******************************************************************************************

//- INCLUDES
#include <iostream>
#include <Xstring.h>
#include <string.h>
#include "Waveform.h"
#include <yat/time/Timer.h>

//- CTOR
WaveForm_data::WaveForm_data(char* lecroyIPAdd)
: ptr_com(0),
  time_to_get_waveformData("")
{
  //- initialisation of all Waveform attributes
  ::memset (ptrRawData, 0, MAX_WAVEFORM_DATA_LENGTH);
  //- struct which contains all Lecroy data
  waveBlockData = 0;
  //- communcation link
  ptr_com = SocketLecroy::get_instance();
  //- connect to Lecroy
  ptr_com->TCP_Connect(lecroyIPAdd);
}

//- DTOR
WaveForm_data::~WaveForm_data()
{
//   std::cout << "\t\tWaveForm_data::DTOR." << std::endl;
  //- close the socket
//   ptr_com->TCP_Disconnect();
//   std::cout << "\t\tWaveForm_data::TCP_Disconnect DNE." << std::endl;
  //- delete the SocketLecroy obj
  if ( ptr_com )
	SocketLecroy::delete_instance();
//   std::cout << "\t\tWaveForm_data::delete_instance DNE." << std::endl;
//   std::cout << "\t\tWaveForm_data::ptrRawData DNE => ptr_com add = " << ptr_com << std::endl;
}

void WaveForm_data::update_channel_data(ChannelData* chdata)
{
//   yat::Timer t;
  get_waveform_data(chdata);
  get_trigger_time_value(chdata);
// std::cout << "\t\tWaveForm_data::update_channel_data -> DONE in " << t.elapsed_msec() << " ms." << std::endl;
}

//- Method to return the raw data of the acquired waveform
void WaveForm_data::get_waveform_data(ChannelData* channelData ) throw (lecroy::WaveformException)
{
std::string	cmd("");
char*	cmdStr = 0;
unsigned short	OFFSET_STRUCT = 0;
std::ostringstream oss;

//- FOR DEBUG : comment out Timer and STD::COUT !!
// yat::Timer t;

//  std::cout << "\t\t\tget_waveform_data ENTERING ..." << std::endl;

  //- init ptr waveblocdata which point on wavedesc_blocs structure
  waveBlockData = 0;

  //- get channel name
  std::string ch_name("") ;
  ch_name = channelData->channel_name_;
//  std::cout << "\t\t\tget_waveform_data -> ch name = " << ch_name << std::endl;

  //- prepare the cmd to get the waveform data
  cmd = ch_name + std::string(":WF? ALL");
  std::size_t in_length = cmd.size() + 1;
  cmdStr = new(std::nothrow) char[in_length];
  ::strncpy(cmdStr, cmd.c_str(), in_length);

  //- send the request
// std::cout << "\t\tget_waveform_data -> write cmd..." << ptr_com << std::endl;
  int out_length = MAX_WAVEFORM_DATA_LENGTH;
  try
  {
	//- erase previsous data
	::memset (ptrRawData, 0, out_length);
	ptr_com->write_read(cmdStr, in_length, ptrRawData, &out_length, true);
//    time_to_read_data = t.elapsed_msec();
// std::cout << "\t\tWaveForm_data::Time to WRITE_READ resp lgth = " << out_length << " data : " << t.elapsed_msec() << std::endl;
  }
  catch(const lecroy::WaveformException &)
  {
    //- XE :
    throw lecroy::WaveformException("OPERATION_FAILED",
                                    "The TCP_ReadDevice() method failed.",
                                    "WaveForm_data::get_waveform_data( ).");
  }
  
  //- delete cmd allocation
  if(cmdStr)
  {
      delete [] cmdStr;
      cmdStr = 0;
  }

  //- calculation of the offset of the structure (it can be 15 or 21)
  unsigned short i = 0;
  for(i=0; i < 22 ; i++)
  {
    if(ptrRawData[i] == 'W' && ptrRawData[i+1] == 'A')
    {
      //- the offset of the structure which contains the context of the waveform acquisition
      OFFSET_STRUCT = i;
      break;
    }
  }

  //- test if the OFFSET_STRUCT is found
  if(!OFFSET_STRUCT)
      throw lecroy::WaveformException("DATA_OUT_OF_RANGE",
									  "The offset of the structure is not found.",
									  "WaveForm_data::get_waveform_data( ).");
// std::cout << "\t\tOFFSET of struct = " << OFFSET_STRUCT << std::endl;

  //- update the struct WAVEDESC_BLOC
  waveBlockData = (WAVEDESC_BLOCK*) (ptrRawData+OFFSET_STRUCT);
  if(!waveBlockData)
      throw lecroy::WaveformException("OUT_OF_MEMORY",
                                      "The pointer for the receive data can't be allocated before the read operation.",
                                      "WaveForm_data::get_waveform_data( ).");

  //- copy data
  channelData->wave_array_count_    = waveBlockData->wave_array_count;
  channelData->vertical_gain_       = waveBlockData->vertical_gain;
  channelData->vertical_offset_     = waveBlockData->vertical_offset;
  channelData->horizontal_interval_ = waveBlockData->horizontal_interval;
  channelData->horizontal_offset_   = waveBlockData->horizontal_offset;
  channelData->nominal_bits_        = waveBlockData->nominal_bits;
  channelData->wave_array_1_        = waveBlockData->wave_array_1;
  channelData->wave_array_2_        = waveBlockData->wave_array_2;
  //- resize vectors
  channelData->raw_waveform_data_.resize(waveBlockData->wave_array_count);
  channelData->vertical_scaled_data_.resize(waveBlockData->wave_array_count);
  //- populate vectors
  for(long idx=0; idx < waveBlockData->wave_array_count; idx++)
  {
    //- raw data
    channelData->raw_waveform_data_[idx] =  (ptrRawData + OFFSET_STRUCT + waveBlockData->wave_descriptor)[idx];
    //- compute and copy scaled data
    channelData->vertical_scaled_data_[idx] = (waveBlockData->vertical_gain * channelData->raw_waveform_data_[idx]) - waveBlockData->vertical_offset;
  }
  
// std::cout << "\t\tWaveForm_data::get_waveform_data done in : " << t.elapsed_msec() << " ms." << std::endl;
}

//- Method to return the trigger time of the acquired waveform
void	WaveForm_data::get_trigger_time_value (ChannelData* channelData)
{
//- The format is : "Date = month, day, year ; Time = hours:minutes:seconds"
std::string str_seconds("");
std::string str_minutes("");
std::string str_hours  ("");
std::string str_days   ("");
std::string str_months ("");
std::string str_years  ("");

  //- hours, min, sec with 2 digits
  str_seconds = XString<double>::convertToString(waveBlockData->trigger_time_seconds);
  if(waveBlockData->trigger_time_seconds<10)
      str_seconds = "0" + str_seconds;

  str_minutes = XString<int>::convertToString((int)waveBlockData->trigger_time_minutes);
  if(waveBlockData->trigger_time_minutes<10)
      str_minutes = "0" + str_minutes;

  str_hours	= XString<int>::convertToString(waveBlockData->trigger_time_hours);
  if(waveBlockData->trigger_time_hours<10)
      str_hours = "0" + str_hours;

  str_days	= XString<int>::convertToString(waveBlockData->trigger_time_days);
  str_months= XString<int>::convertToString(waveBlockData->trigger_time_months);
  str_years	= XString<short>::convertToString(waveBlockData->trigger_time_year);

  //- Construct the string Trigger Time:
  channelData->trigger_time_ = "Date = " + str_months + "/" + str_days + "/" + str_years + " ; Time = " + str_hours + ":" + str_minutes + ":" + str_seconds;
}