using System;
using System.Collections.Generic;
using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core;
///
/// Gen4 Extra Block Info
///
public sealed class BlockInfo4 : BlockInfo
{
private const int SIZE_FOOTER = 0x10;
private readonly int FooterOffset;
public BlockInfo4(uint id, int offset, int length)
{
ID = id;
Offset = offset;
Length = length;
FooterOffset = offset + length - SIZE_FOOTER;
}
public uint GetKey(ReadOnlySpan data) => ReadUInt32LittleEndian(data[Offset..]);
public uint GetMagic(ReadOnlySpan data) => ReadUInt32LittleEndian(data[FooterOffset..]);
public uint GetRevision(ReadOnlySpan data) => ReadUInt32LittleEndian(data[(FooterOffset + 0x4)..]);
public int GetSize(ReadOnlySpan data) => ReadInt32LittleEndian(data[(FooterOffset + 0x8)..]);
public ushort GetID(ReadOnlySpan data) => ReadUInt16LittleEndian(data[(FooterOffset + 0xC)..]);
private ushort GetChecksum(ReadOnlySpan data) => Checksums.CRC16_CCITT(data.Slice(Offset, Length - 2));
private bool IsInitialized(ReadOnlySpan data)
{
return (ID == 0 && GetRevision(data) != 0xFFFFFFFF) || (ID != 0 && GetKey(data) != 0xFFFFFFFF);
}
public bool SizeValid(ReadOnlySpan data)
{
return GetSize(data) == Length;
}
protected override bool ChecksumValid(ReadOnlySpan data)
{
if (!IsInitialized(data))
return true;
ushort chk = GetChecksum(data);
if (chk != ReadUInt16LittleEndian(data[(FooterOffset + 14)..]))
return false;
return true;
}
public bool IsValid(ReadOnlySpan data)
{
return IsInitialized(data) && SizeValid(data) && ChecksumValid(data);
}
protected override void SetChecksum(Span data)
{
if (!IsInitialized(data))
return;
ushort chk = GetChecksum(data);
WriteUInt16LittleEndian(data[(FooterOffset + 14)..], chk);
}
private void SetMagic(Span data, uint magic)
{
if (!IsInitialized(data))
return;
WriteUInt32LittleEndian(data[FooterOffset..], magic);
}
public static void SetMagics(IEnumerable blocks, Span data, uint magic)
{
foreach (var b in blocks)
b.SetMagic(data, magic);
}
}
public static partial class Extensions
{
public static void SetMagics(this IEnumerable blocks, Span data, uint magic) => BlockInfo4.SetMagics(blocks, data, magic);
}