context: using Reko.Core;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Reko.Environments.Trs80.Dmk
  {
      internal class Track
      {
          private List<Sector> m_sectors = new List<Sector>();
  
          private int m_dmkOffset = -1;
          private byte[] m_header = new byte[128];
          private byte[] m_data;
          private bool m_twoByteSingleDensity = true;
  
          public long Length
          {
              get
              {
                  if (this.isEmpty())
                  {
                      return 0L;
                  }
                  return this.m_data.LongLength;
              }
          }
  
          public int SectorCount
          {
              get
              {
                  return this.m_sectors.Count;
              }
          }
  
          public bool twoByteSingleDensity
          {
              get
              {
                  return this.m_twoByteSingleDensity;
              }
              set
              {
                  this.m_twoByteSingleDensity = value;
              }
          }
  
          public int TrackNumber { get; set; }
  
          public int Side { get; set; }
  
          public IEnumerable<Sector> Sectors { get { return m_sectors; } }
  
          public static ushort calc_crc(ushort crc, byte bt)
          {
              uint num = Convert.ToUInt32((int)bt << 8);
              uint num2 = Convert.ToUInt32(crc);
              for (int i = 0; i < 8; i++)
              {
                  bool flag = ((num2 ^ num) & 32768u) == 32768u;
                  num2 = Convert.ToUInt32((long)((ulong)((ulong)num2 << 1) ^ (ulong)(flag ? 4129L : 0L)));
                  num2 &= 65535u;
                  num <<= 1;
              }
              return Convert.ToUInt16(num2);
          }
  
          public Track()
          {
              m_data = null!;
          }
  
          public Track(int number, int side) : this()
          {
              this.TrackNumber = number;
              this.Side = side;
          }
  
          public byte ReadByte(long index)
          {
              if (this.isEmpty())
              {
                  return 0;
              }
              if (index >= this.m_data.LongLength)
              {
                  return 0;
              }
              return this.m_data[(int)(checked((IntPtr)index))];
          }
  
  
  
          public byte dataMarker(int index)
          {
              if (index < 0)
              {
                  return 0;
              }
              if (index >= this.m_sectors.Count)
              {
                  return 0;
              }
              return this.m_sectors[index].Marker;
          }
  
          public byte crc1(int index)
          {
              if (index < 0)
              {
                  return 0;
              }
              if (index >= this.m_sectors.Count)
              {
                  return 0;
              }
              return this.m_sectors[index].Crc1;
          }
  
          public byte crc2(int index)
          {
              if (index < 0)
              {
                  return 0;
              }
              if (index >= this.m_sectors.Count)
              {
                  return 0;
              }
              return this.m_sectors[index].Crc2;
          }
  
          public byte datacrc1(int index)
          {
              if (index < 0)
              {
                  return 0;
              }
              if (index >= this.m_sectors.Count)
              {
                  return 0;
              }
              return this.m_sectors[index].DataCrc1;
          }
  
          public byte datacrc2(int index)
          {
              if (index < 0)
              {
                  return 0;
              }
              if (index >= this.m_sectors.Count)
              {
                  return 0;
              }
              return this.m_sectors[index].DataCrc2;
          }
  
          public bool goodHeaderCRC(int index)
          {
              return index >= 0 && index < this.m_sectors.Count && this.m_sectors[index].goodHeaderCRC;
          }
  
          public bool goodDataCRC(int index)
          {
              return index >= 0 && index < this.m_sectors.Count && this.m_sectors[index].goodDataCRC;
          }
  
          public int findSectorAndTrack(int track, int sector, bool doubleDensity)
          {
              for (int i = 0; i < this.m_sectors.Count; i++)
              {
                  if (this.m_sectors[i].Track == track && this.m_sectors[i].sector == sector && this.m_sectors[i].doubleDensity == doubleDensity)
                  {
                      return i;
                  }
              }
              return -1;
          }
  
          public int reportedSector(int index)
          {
              if (index < 0)
              {
                  return -1;
              }
              if (index >= this.m_sectors.Count)
              {
                  return -1;
              }
              return this.m_sectors[index].sector;
          }
  
          public int reportedTrack(int index)
          {
              if (index < 0)
              {
                  return -1;
              }
              if (index >= this.m_sectors.Count)
              {
                  return -1;
              }
              return this.m_sectors[index].Track;
          }
  
          public bool doubleDensity(int index)
          {
              return index >= 0 && index < this.m_sectors.Count && this.m_sectors[index].doubleDensity;
          }
  
          public IByteSource? sectorData(int index)
          {
              if (index < 0)
              {
                  return null;
              }
              if (index >= this.m_sectors.Count)
              {
                  return null;
              }
              return this.m_sectors[index];
          }
  
          private bool isEmpty()
          {
              return this.m_data == null || this.m_data.Length == 0;
          }
  
          public void setHeader(byte[] data, int startPosition)
          {
              Buffer.BlockCopy(data, startPosition, this.m_header, 0, 128);
          }
  
          public void setData(byte[] data, int startPosition, int length)
          {
              this.m_dmkOffset = startPosition;
              this.m_data = new byte[length];
              Buffer.BlockCopy(data, startPosition, this.m_data, 0, length);
          }
  
          public void ParseSectors()
  		{
  			this.m_sectors.Clear();
  			if (this.m_data == null)
  			{
  				return;
  			}
  			int i = 0;
  			int num = this.m_header.Length;
  			int num2 = 0;
  			while (i < num)
  			{
  				int num3 = Convert.ToInt32(this.m_header[i]) + (Convert.ToInt32(this.m_header[i + 1]) << 8);
  				i += 2;
  				if (num3 == 0)
  				{
  					return;
  				}
  				bool flag = (num3 & 32768) == 32768;
  				int num4 = (num3 & 16383) - 128;
  				if (num4 >= 0 && num4 >= num2)
  				{
  					num2 = num4;
  					if (num4 >= this.m_data.Length)
  					{
  						return;
  					}
  					Sector sector = new Sector();
  					sector.doubleDensity = flag;
  					if (!flag && this.m_twoByteSingleDensity)
  					{
  						sector.DoubleBytes = true;
  					}
  					byte b = this.m_data[num4];
  					bool flag2 = b == 254;
  					ushort num5 = 0;
  					if (flag2)
  					{
  						num5 = Track.calc_crc(Convert.ToUInt16(flag ? 52660 : 65535), b);
  					}
  					num4++;
  					if (!flag && this.m_twoByteSingleDensity)
  					{
  						num4++;
  					}
  					if (num4 >= this.m_data.Length)
  					{
  						this.m_sectors.Add(sector);
  					}
  					else
  					{
  						int track = Convert.ToInt32(this.m_data[num4]);
  						if (flag2)
  						{
  							num5 = Track.calc_crc(num5, this.m_data[num4]);
  						}
  						num4++;
  						if (!flag && this.m_twoByteSingleDensity)
  						{
  							num4++;
  						}
  						sector.Track = track;
  						if (num4 >= this.m_data.Length)
  						{
  							this.m_sectors.Add(sector);
  						}
  						else
  						{
  							int side = Convert.ToInt32(this.m_data[num4]);
  							if (flag2)
  							{
  								num5 = Track.calc_crc(num5, this.m_data[num4]);
  							}
  							num4++;
  							if (!flag && this.m_twoByteSingleDensity)
  							{
  								num4++;
  							}
  							sector.Side = side;
  							if (num4 >= this.m_data.Length)
  							{
  								this.m_sectors.Add(sector);
  							}
  							else
  							{
  								int sector2 = Convert.ToInt32(this.m_data[num4]);
  								if (flag2)
  								{
  									num5 = Track.calc_crc(num5, this.m_data[num4]);
  								}
  								num4++;
  								if (!flag && this.m_twoByteSingleDensity)
  								{
  									num4++;
  								}
  								sector.sector = sector2;
  								if (num4 >= this.m_data.Length)
  								{
  									this.m_sectors.Add(sector);
  								}
  								else
  								{
  									int sizeCode = Convert.ToInt32(this.m_data[num4]);
  									if (flag2)
  									{
  										num5 = Track.calc_crc(num5, this.m_data[num4]);
  									}
  									num4++;
  									if (!flag && this.m_twoByteSingleDensity)
  									{
  										num4++;
  									}
  									sector.SizeCode = sizeCode;
  									int num6 = 0;
  									if (i + 1 < this.m_header.Length)
  									{
  										num6 = Convert.ToInt32(this.m_header[i]) + (Convert.ToInt32(this.m_header[i + 1]) << 8);
  										num6 = (num6 & 16383) - 128;
  										if (num6 < 0)
  										{
  											num6 = 0;
  										}
  									}
  									if (flag2)
  									{
  										num5 = Track.calc_crc(num5, this.m_data[num4]);
  										sector.Crc1 = this.m_data[num4];
  									}
  									num4++;
  									if (!flag && this.m_twoByteSingleDensity)
  									{
  										num4++;
  									}
  									if (num4 >= this.m_data.Length)
  									{
  										this.m_sectors.Add(sector);
  									}
  									else
  									{
  										if (flag2)
  										{
  											num5 = calc_crc(num5, this.m_data[num4]);
  											sector.Crc2 = this.m_data[num4];
  										}
  										num4++;
  										if (!flag && this.m_twoByteSingleDensity)
  										{
  											num4++;
  										}
  										if (num4 >= this.m_data.Length)
  										{
  											this.m_sectors.Add(sector);
  										}
  										else
  										{
  											sector.goodHeaderCRC = (num5 == 0);
  
gt: 											sector.actualSize = this.sectorSize(sizeCode, flag);