/***************************************************************************
**
**  This file is part of GeopsyCore.
**
**  GeopsyCore 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 3 of the License, or
**  (at your option) any later version.
**
**  GeopsyCore 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 Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2009-08-26
**  Copyright: 2009-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef SEGYTRACEHEADER_H
#define SEGYTRACEHEADER_H

#include <QGpCoreMath.h>

#include "SignalFileFormat.h"
#include "GeopsyCoreDLLExport.h"

namespace GeopsyCore {

#pragma pack(1)     /* set alignment to 1 byte boundary */

class GEOPSYCORE_EXPORT SEGYTraceHeader
{
  TRANSLATIONS("SEGYTraceHeader")
public:
  SEGYTraceHeader();

  static SignalFileFormat::Format determineByteOrderSEGY(QString fileName, int verbosity);
  static SignalFileFormat::Format determineByteOrderSU(QString fileName, int verbosity);
  static bool isSampleCodingValid(qint16 sampleCoding);

  static double IBMFloat2ieee(qint32 val);

  void read(QDataStream& s);
  void write(QDataStream& s);

  bool setNSamples(int n);

  enum Delay {NoDelay, SUDelay, SEGYDelay};
  DateTime startTime(Delay d) const;
  void setStartTime(const DateTime& t, bool su);

  Point source() const;
  Point receiver() const;

  bool setCoordinateFactor(const Point& rec, const Point& src);
  bool setElevationFactor(const Point& rec, const Point& src);
  void setReceiver(const Point& rec);
  void setSource(const Point& src);

  union {
    struct {
      qint32 raw0[7];
      qint16 raw1[4];
      qint32 raw2[8];
      qint16 raw3[2];
      qint32 raw4[4];
      qint16 raw5[46];
      qint32 raw6[5];
      qint16 raw7[20];
    } raw;
    struct {
      qint32 traceNumberInLine;              // 1-4
      qint32 traceNumberInFile;              // 5-8
      qint32 originalRecordNumber;           // 9-12
      qint32 traceNumberInRecord;            // 13-16
      qint32 sourceNumber;                   // 17-20
      qint32 ensembleNumber;                 // 21-24
      qint32 traceNumberInEnsemble;          // 25-28
      qint16 traceIndentificationCode;       // 29-30
      qint16 numberSumVertical;              // 31-32
      qint16 numberStackHorizontal;          // 33-34
      qint16 dataUse;                        // 35-36
      qint32 sourceReceiverDistance;         // 37-40
      qint32 receiverElevation;              // 41-44
      qint32 sourceSurfaceElevation;         // 45-48
      qint32 sourceDepth;                    // 49-52
      qint32 receiverDatumElevation;         // 53-56
      qint32 sourceDatumElevation;           // 57-60
      qint32 sourceWaterDepth;               // 61-64
      qint32 receiverWaterDepth;             // 65-68
      qint16 elevationFactor;                // 69-70
      qint16 coordinateFactor;               // 71-72
      qint32 sourceXCoordinate;              // 73-76
      qint32 sourceYCoordinate;              // 77-80
      qint32 receiverXCoordinate;            // 81-84
      qint32 receiverYCoordinate;            // 85-88
      qint16 coordinateUnit;                 // 89-90
      qint16 weatheringVelocity;             // 91-92
      qint16 subWeatheringVelocity;          // 93-94
      qint16 sourceUpholeTime;               // 95-96
      qint16 receiverUpholeTime;             // 97-98
      qint16 sourceStaticCorrection;         // 99-100
      qint16 receiverStaticCorrection;       // 101-102
      qint16 totalStaticCorrection;          // 103-104
      qint16 lagTimeA;                       // 105-106
      qint16 lagTimeB;                       // 107-108
      qint16 delayRecordingTime;             // 109-110 (milliseconds)
      qint16 startMuteTime;                  // 111-112
      qint16 endMuteTime;                    // 113-114
      quint16 sampleNumber;                  // 115-116
      quint16 sampleInterval;                // 117-118
      qint16 gainType;                       // 119-120
      qint16 gainConstant;                   // 121-122
      qint16 initialGain;                    // 123-124
      qint16 correlated;                     // 125-126
      qint16 startSweepFrequency;            // 127-128
      qint16 endSweepFrequency;              // 129-130
      qint16 lengthSweepFrequency;           // 131-132
      qint16 sweepType;                      // 133-134
      qint16 startSweepTaper;                // 135-136
      qint16 endSweepTaper;                  // 137-138
      qint16 taperType;                      // 139-140
      qint16 aliasFilterFrequency;           // 141-142
      qint16 aliasFilterSlope;               // 143-144
      qint16 notchFilterFrequency;           // 145-146
      qint16 notchFilterSlope;               // 147-148
      qint16 lowCutFrequency;                // 149-150
      qint16 highCutFrequency;               // 151-152
      qint16 lowCutSlope;                    // 153-154
      qint16 highCutSlope;                   // 155-156
      qint16 year;                           // 157-158
      qint16 day;                            // 159-160
      qint16 hour;                           // 161-162
      qint16 minute;                         // 163-164
      qint16 second;                         // 165-166
      qint16 timeBase;                       // 167-168
      qint16 weightFactor;                   // 169-170
      qint16 ignored01;                      // 171-172
      qint16 ignored02;                      // 173-174
      qint16 ignored03;                      // 175-176
      qint16 ignored04;                      // 177-178
      qint16 ignored05;                      // 179-180
      qint32 ignored06;                      // 181-184
      qint32 ignored07;                      // 185-188
      qint32 ignored08;                      // 189-192
      qint32 ignored09;                      // 193-196
      qint32 ignored10;                      // 197-200
      qint16 ignored11;                      // 201-202
      qint16 amplitudeUnit;                  // 203-204
      qint32 ignored12; qint16 ignored13;    // 205-210
      qint16 ignored14;                      // 211-212
      qint16 ignored15;                      // 213-214
      qint16 timeFactor;                     // 215-216
      qint16 ignored16;                      // 217-218
      qint16 ignored17; qint32 ignored18;    // 219-224
      qint32 ignored19; qint16 ignored20;    // 225-230
      qint16 ignored21;                      // 231-232
      qint32 ignored22, ignored23;           // 233-240
    } field;
  };
private:
  static bool suCanReadAll(QDataStream& s, qint64 fileSize);
  double decodeCoordinateFactor() const;
  double decodeElevationFactor() const;
  double decodeTimeFactor() const;
  double encodeCoordinateFactor() const;
  double encodeElevationFactor() const;
  double encodeTimeFactor() const;
  static qint16 factor(double min, double max, double theoreticalMaximum);
};

#pragma pack()   // restore original alignment

} // namespace GeopsyCore

#endif // SEGYTRACEHEADER_H
