context: /*
  Copyright (C) 2010 Zone Five Software
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.
  
  This library 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
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library. If not, see <http://www.gnu.org/licenses/>.
   */
  // Author: Aaron Averill
  
  
  using System;
  using System.Collections.Generic;
  using System.Windows.Forms;
  using ZoneFiveSoftware.Common.Visuals;
  
  namespace ZoneFiveSoftware.SportTracks.Device.Globalsat
  {
      class Gb580Packet : GlobalsatPacket2
      {
          public Gb580Packet(FitnessDevice_Globalsat device) : base(device) { }
  
          private int ReadHeader(Header header, int offset)
          {
              header.StartTime = ReadDateTime(offset).ToUniversalTime().AddHours(this.FitnessDevice.configInfo.HoursAdjustment);
              header.TrackPointCount = ReadInt16(offset + 6);
              header.TotalTime = TimeSpan.FromSeconds(FromGlobTime(ReadInt32(offset + 8)));
              header.TotalDistanceMeters = ReadInt32(offset + 12);
              header.LapCount = ReadInt16(offset + 16);
              return 18;
          }
  
          public override IList<TrackFileHeader> UnpackTrackHeaders()
          {
              int numTrains = this.PacketLength / TrackHeaderLength;
              IList<TrackFileHeader> trains = new List<TrackFileHeader>();
              int offset = 0;
              for (int i = 0; i < numTrains; i++)
              {
                  TrackFileHeader train = new TrackFileHeader();
                  ReadHeader(train, offset);
                  train.TrackPointIndex = ReadInt16(offset + 18);
                  //20 listed as TrainLap record index too
                  //train.LapIndexEndPt = ReadInt16(offset + 20);
                  //cDataType or MultiSport 22
                  //pad 23
                  offset += TrackHeaderLength;
                  trains.Add(train);
              }
              CheckOffset(this.PacketLength, offset);
              return trains;
          }
  
          public override Train UnpackTrainHeader()
          {
              if (pVersion < 0)
              {
                  if (this.PacketLength == TrainDataHeaderLength)
                  {
                      pVersion = 0;
                  }
                  else if (this.PacketLength == TrainDataHeaderLength + 8)
                  {
                      pVersion = 1;
                  }
                  //Other is unknown, caught below
              }
              CheckOffset(this.PacketLength, TrainDataHeaderLength);
              if (this.PacketLength < TrainDataHeaderLength)
              {
                  return null;
              }
  
              Train train = new Train();
              ReadHeader(train, 0);
              train.TotalCalories = ReadInt16(24); //2 pad
              train.MaximumSpeed = FromGlobSpeed(ReadInt32(28));
              train.MaximumHeartRate = this.PacketData[32];
              train.AverageHeartRate = this.PacketData[33];
              train.TotalAscend = ReadInt16(34);
              train.TotalDescend = ReadInt16(36);
              //train.MinimumAltitude = ReadInt16(38);
              //train.MaximumAltitude = ReadInt16(40);
              train.AverageCadence = ReadInt16(42);
              train.MaximumCadence = ReadInt16(44);
              train.AveragePower = ReadInt16(46);
              train.MaximumPower = ReadInt16(48);
              //5 bytes of SportType
              //pad
  
              //if (pVersion > 0)
              //{
              //    lap.AverageTemperature = ReadInt16(offset + 56);
              //    lap.MaximumTemperature = ReadInt16(offset + 58);
              //    lap.MinimumTemperature = ReadInt16(offset + 60);
              //pad 2 bytes
              //}
  
              return train;
          }
  
          public override IList<Lap> UnpackLaps()
          {
              if (this.PacketLength < TrackHeaderLength ||
                  this.GetTrainContent() != HeaderTypeLaps)
              {
                  ReportOffset(this.PacketLength, TrackHeaderLength);
                  return new List<Lap>();
              }
  
              IList<Lap> laps = new List<Lap>();
  
              int offset = TrackHeaderLength;
  
              while (offset <= this.PacketLength - TrackLapLength)
              {
                  Lap lap = new Lap();
  
                  lap.EndTime = TimeSpan.FromSeconds(FromGlobTime(ReadInt32(offset)));
                  lap.LapTime = TimeSpan.FromSeconds(FromGlobTime(ReadInt32(offset + 4)));
                  lap.LapDistanceMeters = ReadInt32(offset + 8);
                  lap.LapCalories = ReadInt16(offset + 12); //pad 2
                  lap.MaximumSpeed = FromGlobSpeed(ReadInt32(offset + 16));
                  lap.MaximumHeartRate = this.PacketData[offset + 20];
                  lap.AverageHeartRate = this.PacketData[offset + 21];
                  lap.MinimumAltitude = ReadInt16(offset + 22);
                  lap.MaximumAltitude = ReadInt16(offset + 24);
                  lap.AverageCadence = ReadInt16(offset + 26);
                  lap.MaximumCadence = ReadInt16(offset + 28);
                  lap.AveragePower = ReadInt16(offset + 30);
                  lap.MaximumPower = ReadInt16(offset + 32);
                  //byte multisport
                  //pad
                  //if (pVersion > 0)
                  //{
                  //    lap.AverageTemperature = ReadInt16(offset + 36);
                  //    lap.MaximumTemperature = ReadInt16(offset + 38);
                  //    lap.MinimumTemperature = ReadInt16(offset + 40);
                  //}
                  //int offset2 = 0;
                  //if (pVersion > 0) { offset2 = 2; }
                  //lap.StartPointIndex = ReadInt16(TrackLapLength-4-offset2);
                  //lap.EndPointIndex = ReadInt16(TrackLapLength-2-offset2);
                  laps.Add(lap);
                  offset += TrackLapLength;
              }
              CheckOffset(this.PacketLength, offset);
              return laps;
          }
  
          public override IList<TrackPoint> UnpackTrackPoints()
          {
              if (this.PacketLength < TrackHeaderLength ||
                  this.GetTrainContent() != HeaderTypeTrackPoints)
              {
                  ReportOffset(this.PacketLength, TrackHeaderLength);
                  return new List<TrackPoint>();
              }
  
              IList<TrackPoint> points = new List<TrackPoint>((this.PacketLength - TrackHeaderLength) / TrackPointLength);
  
              int offset = TrackHeaderLength;
              while (offset <= this.PacketLength - TrackPointLength)
              {
                  TrackPoint point = new TrackPoint();
                  point.Latitude = (double)ReadLatLon(offset);
                  point.Longitude = (double)ReadLatLon(offset + 4);
                  point.Altitude = ReadInt16(offset + 8); //2 byte padding
                  point.Speed = FromGlobSpeed(ReadInt32(offset + 12));
                  point.HeartRate = this.PacketData[offset + 16]; //3 byte padding
                  point.IntervalTime = FromGlobTime(ReadInt32(offset + 20));
                  point.Cadence = ReadInt16(offset + 24);
                  point.PowerCadence = ReadInt16(offset + 26);
                  point.Power = ReadInt16(offset + 28);
                  if (pVersion > 0) { point.Temperature = ReadInt16(offset + 30); }
                  points.Add(point);
                  offset += TrackPointLength;
              }
              CheckOffset(this.PacketLength, offset);
              return points;
          }
  
          //Trackstart without laps
          public override GlobalsatPacket SendTrackStart(Train trackFile)
          {
              if (pVersion < 0)
              {
                  String s = "Is Firmware updated to F-GGB-2O-1402241?";
                  if (MessageDialog.Show(s, "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                  {
                      pVersion = 1;
                  }
                  else
                  {
                      pVersion = 0;
                  }
              }
  
              Int16 nrLaps = 1;
              Int16 totalLength = (Int16)TrainDataHeaderLength;
              this.InitPacket(CommandSendTrackStart, totalLength);
  
              int offset = 0;
  
              offset += WriteTrackHeader(offset, nrLaps, trackFile);
  
              offset += this.Write(offset, trackFile.TotalCalories); offset += 2;
              offset += this.Write32(offset, ToGlobSpeed(trackFile.MaximumSpeed));
              this.PacketData[offset++] = (byte)trackFile.MaximumHeartRate;
              this.PacketData[offset++] = (byte)trackFile.AverageHeartRate;
              offset += this.Write(offset, trackFile.TotalAscend);
              offset += this.Write(offset, trackFile.TotalDescend);
  
  
gt:             offset += this.Write(offset, 0); // min altitude