// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

/*! \file intanlib.h
 *  \author Christoph Schmidt-Hieber
 *  \date 2017-03-11
 *  \brief Reads Intan Technologies CLAMP data file generated by controller GUI.
 */

/*
Mostly a Python version of read_Intan_CLP_file.m from
http://www.intantech.com/files/Intan_CLAMP_software_compiled_v1_0.zip
as of 2016-11-05

Example:
>>> import matplotlib.pyplot as plt
>>> import intan
>>> intan_file = intan.IntanFile('myexperiment_A_160916_142731.clp')
>>> plt.plot(intan_file.data["Time"], intan_file.data["Measured"])
>>> intan_file = intan.IntanFile('myexperiment_AUX_160916_142731.clp')
>>> plt.plot(intan_file.data["Time"], intan_file.data["ADC"][1])
*/
#ifndef INTANLIB_H
#define INTANLIB_H

#if __cplusplus > 199711L
#include <cstdint>
#else
#include <boost/cstdint.hpp>
#endif

#include "./../stfio.h"

#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#endif

class Recording;

static const int MAX_REGISTERS = 14;
static const uint32_t MAGIC_NUMBER = 0xf3b1a481;

struct Segment {
    uint8_t waveformNumber;
    uint32_t tOffset;
    uint32_t startIndex;
    uint32_t endIndex;
    float appliedValue;
};

struct VoltageClampSettings {
    float holdingVoltage;
    float nominalResistance;
    float resistance;
    float desiredBandwidth;
    float actualBandwidth;
};

struct CurrentClampSettings {
    float holdingCurrent;
    float currentStepSize;
};

struct HeaderSettings {
    uint8_t enableCapacitiveCompensation;
    float capCompensationMagnitude;
    float filterCutoff;
    float pipetteOffset;
    float samplingRate;
    float cellRs;
    float cellRm;
    float cellCm;
    uint8_t isVoltageClamp;
    uint8_t vClampX2Mode;
    VoltageClampSettings vcSettings;
    CurrentClampSettings ccSettings;
    std::vector<Segment> waveform;
};

struct Calibration {
    uint8_t coarse;
    uint8_t fine;
};

struct ChannelHeader {
    uint16_t registers[MAX_REGISTERS];
    uint32_t differenceAmpResidual;
    uint32_t voltageAmpResidual;
    Calibration bestCalibration[2][4];
    float rFeedback[5];
    float desiredBandwidth;
};

struct ChipHeader {
    std::vector<ChannelHeader> channels;
    uint16_t chipRegisters[4];
};

struct IntanHeader {
    int16_t version_major;
    int16_t version_minor;
    int16_t datatype;
    int16_t date_Year;
    int16_t date_Month;
    int16_t date_Day;
    int16_t date_Hour;
    int16_t date_Minute;
    int16_t date_Second;
    std::vector<ChipHeader> Chips;
    HeaderSettings Settings;
    uint16_t numADCs;

};

namespace stfio {

//! Open an Intan file and store its contents to a Recording object.
/*! \param fName The full path to the file to be opened.
 *  \param ReturnData On entry, an empty Recording object. On exit,
 *         the data stored in \e fName.
 *  \param progress True if the progress dialog should be updated.
 */
    void importIntanFile(const std::string &fName, Recording &ReturnData, ProgressInfo& progDlg);

}
#endif