#include <EDK.h>
#include "General.h"
#include "CBMFileName.h"


////////////////////////////////////////////////////////////////////////////////
// parse CBM file name and set flags

void CBMFileName::Parse(CString NewName, int iChannel, int iMaxLength) {

  // set defaults
  Name.Empty();
  fDirectory = FALSE;
  fOverwrite = FALSE;
  fWildcards = FALSE;
  if (iChannel < 2) {
    cType = 'P';
  } else {
    cType = '?';
  }
  if (iChannel == 1) {
    cMode = 'W';
  } else {
    cMode = 'R';
  }
  bUnit = 0;
  bRecordLength = 0;

  // check for directory and overwrite
  const char* pcName = NewName;
  const char* pcEnd = pcName + NewName.GetLength();
  if (pcName < pcEnd) {
    if (*pcName == '$') {
      fDirectory = TRUE;
      cType = '?';
      pcName++;
    } else if (*pcName == '@') {
      fOverwrite = TRUE;
      pcName++;
    }
  }
 
  // get unit and skip characters before colon
  if (pcName < pcEnd) {
    char* pcColon = (char*)memchr(pcName, ':', pcEnd - pcName);
    if (pcColon) {
      if (pcColon > pcName && isdigit(pcColon[-1])) {
        bUnit = (byte)(pcColon[-1] & 15);
      }
      pcName = pcColon + 1;
    }
  }
 
  // get type and mode
  const char* pcEndName = NULL;
  for (const char* pc = pcName; pc < pcEnd; pc++) {
    if (*pc == ',' || *pc == '=') {
      if (pcEndName == NULL) {
        pcEndName = pc;
      }
      pc++;
      int iRest = pcEnd - pc;
      if (iRest < 1) {
        error("30,MISSING FILE TYPE,00,00");
      }
      switch (*pc) {
      case 'P': // PRG
      case 'S': // SEQ
      case 'U': // USR
      case 'D': // DEL
      case 'C': // CBM directory
        cType = *pc;
        break;
      case 'L': // REL
        cType = 'R';
        if (iRest >= 2 && pc[1] == ',') {
          if (iRest < 3) {
            error("30,MISSING RECORD SIZE,00,00");
          }
          bRecordLength = (byte)pc[2];
          pc += 2;
        }
        break;
      case 'R': // READ
      case 'W': // WRITE
      case 'A': // APPEND
        cMode = *pc;
        break;
      }
    }
  }

  // get name
  if (pcEndName == NULL) {
    pcEndName = pcEnd;
  }
  int iLength = pcEndName - pcName;
  if (iLength > 0) {
    if (iLength > iMaxLength) {
      iLength = iMaxLength;
    }
    if (memchr(pcName, '*', iLength) != NULL || memchr(pcName, '?', iLength) != NULL) {
      fWildcards = TRUE;
    }
    Name = CString(pcName, iLength);
  } else {
    if (fDirectory) {
      fWildcards = TRUE;
      Name = "*";
    } else {
      error("34,MISSING FILE NAME,00,00");
    }
  }
}


////////////////////////////////////////////////////////////////////////////////
// compare name with directory entry

flag CBMFileName::Match(char* pc, char* pcEnd) {

  const char* pcName = Name;
  const char* pcNameEnd = pcName + Name.GetLength();

  while (pc < pcEnd) {
    if (pcName >= pcNameEnd) {
      return FALSE;
    }
    if (*pcName != *pc && *pcName != '?') {
      return *pcName == '*';
    }
    pc++;
    pcName++;
  }

  return pcName >= pcNameEnd || *pcName == '*';
}


////////////////////////////////////////////////////////////////////////////////
// constructor

CBMFileName::CBMFileName() {
  fDirectory = FALSE;
  fOverwrite = FALSE;
  fWildcards = FALSE;
  cType = '?';
  cMode = '?';
  bUnit = 0;
  bRecordLength = 0;
}
