package jxl.read.biff;

import common.Logger;
import jxl.WorkbookSettings;
import jxl.biff.IntegerHelper;
import jxl.biff.RecordData;
import jxl.biff.StringHelper;

public class SupbookRecord extends RecordData {
  private static Logger logger = Logger.getLogger(SupbookRecord.class);
  
  private Type type;
  
  private int numSheets;
  
  private String fileName;
  
  private String[] sheetNames;
  
  private static class Type {
    private Type() {}
  }
  
  public static final Type INTERNAL = new Type();
  
  public static final Type EXTERNAL = new Type();
  
  public static final Type ADDIN = new Type();
  
  public static final Type LINK = new Type();
  
  public static final Type UNKNOWN = new Type();
  
  SupbookRecord(Record t, WorkbookSettings ws) {
    super(t);
    byte[] data = getRecord().getData();
    if (data.length == 4) {
      if (data[2] == 1 && data[3] == 4) {
        this.type = INTERNAL;
      } else if (data[2] == 1 && data[3] == 58) {
        this.type = ADDIN;
      } else {
        this.type = UNKNOWN;
      } 
    } else if (data[0] == 0 && data[1] == 0) {
      this.type = LINK;
    } else {
      this.type = EXTERNAL;
    } 
    if (this.type == INTERNAL)
      this.numSheets = IntegerHelper.getInt(data[0], data[1]); 
    if (this.type == EXTERNAL)
      readExternal(data, ws); 
  }
  
  private void readExternal(byte[] data, WorkbookSettings ws) {
    this.numSheets = IntegerHelper.getInt(data[0], data[1]);
    int ln = IntegerHelper.getInt(data[2], data[3]) - 1;
    int pos = 0;
    if (data[4] == 0) {
      int encoding = data[5];
      pos = 6;
      if (encoding == 0) {
        this.fileName = StringHelper.getString(data, ln, pos, ws);
        pos += ln;
      } else {
        this.fileName = getEncodedFilename(data, ln, pos);
        pos += ln;
      } 
    } else {
      int encoding = IntegerHelper.getInt(data[5], data[6]);
      pos = 7;
      if (encoding == 0) {
        this.fileName = StringHelper.getUnicodeString(data, ln, pos);
        pos += ln * 2;
      } else {
        this.fileName = getUnicodeEncodedFilename(data, ln, pos);
        pos += ln * 2;
      } 
    } 
    this.sheetNames = new String[this.numSheets];
    for (int i = 0; i < this.sheetNames.length; i++) {
      ln = IntegerHelper.getInt(data[pos], data[pos + 1]);
      if (data[pos + 2] == 0) {
        this.sheetNames[i] = StringHelper.getString(data, ln, pos + 3, ws);
        pos += ln + 3;
      } else if (data[pos + 2] == 1) {
        this.sheetNames[i] = StringHelper.getUnicodeString(data, ln, pos + 3);
        pos += ln * 2 + 3;
      } 
    } 
  }
  
  public Type getType() {
    return this.type;
  }
  
  public int getNumberOfSheets() {
    return this.numSheets;
  }
  
  public String getFileName() {
    return this.fileName;
  }
  
  public String getSheetName(int i) {
    return this.sheetNames[i];
  }
  
  public byte[] getData() {
    return getRecord().getData();
  }
  
  private String getEncodedFilename(byte[] data, int ln, int pos) {
    StringBuffer buf = new StringBuffer();
    int endpos = pos + ln;
    while (pos < endpos) {
      char c = (char)data[pos];
      if (c == '\001') {
        pos++;
        c = (char)data[pos];
        buf.append(c);
        buf.append(":\\\\");
      } else if (c == '\002') {
        buf.append('\\');
      } else if (c == '\003') {
        buf.append('\\');
      } else if (c == '\004') {
        buf.append("..\\");
      } else {
        buf.append(c);
      } 
      pos++;
    } 
    return buf.toString();
  }
  
  private String getUnicodeEncodedFilename(byte[] data, int ln, int pos) {
    StringBuffer buf = new StringBuffer();
    int endpos = pos + ln * 2;
    while (pos < endpos) {
      char c = (char)IntegerHelper.getInt(data[pos], data[pos + 1]);
      if (c == '\001') {
        pos += 2;
        c = (char)IntegerHelper.getInt(data[pos], data[pos + 1]);
        buf.append(c);
        buf.append(":\\\\");
      } else if (c == '\002') {
        buf.append('\\');
      } else if (c == '\003') {
        buf.append('\\');
      } else if (c == '\004') {
        buf.append("..\\");
      } else {
        buf.append(c);
      } 
      pos += 2;
    } 
    return buf.toString();
  }
}
