package jxl.write.biff;

import common.Assert;
import common.Logger;
import jxl.WorkbookSettings;
import jxl.biff.EncodedURLHelper;
import jxl.biff.IntegerHelper;
import jxl.biff.StringHelper;
import jxl.biff.Type;
import jxl.biff.WritableRecordData;

class SupbookRecord extends WritableRecordData {
  private static Logger logger = Logger.getLogger(SupbookRecord.class);
  
  private SupbookType type;
  
  private byte[] data;
  
  private int numSheets;
  
  private String fileName;
  
  private String[] sheetNames;
  
  private WorkbookSettings workbookSettings;
  
  private static class SupbookType {
    private SupbookType() {}
  }
  
  public static final SupbookType INTERNAL = new SupbookType();
  
  public static final SupbookType EXTERNAL = new SupbookType();
  
  public static final SupbookType ADDIN = new SupbookType();
  
  public static final SupbookType LINK = new SupbookType();
  
  public static final SupbookType UNKNOWN = new SupbookType();
  
  public SupbookRecord(int sheets, WorkbookSettings ws) {
    super(Type.SUPBOOK);
    this.numSheets = sheets;
    this.type = INTERNAL;
    this.workbookSettings = ws;
  }
  
  public SupbookRecord(String fn, WorkbookSettings ws) {
    super(Type.SUPBOOK);
    this.fileName = fn;
    this.numSheets = 1;
    this.sheetNames = new String[0];
    this.workbookSettings = ws;
    this.type = EXTERNAL;
  }
  
  public SupbookRecord(jxl.read.biff.SupbookRecord sr, WorkbookSettings ws) {
    super(Type.SUPBOOK);
    this.workbookSettings = ws;
    if (sr.getType() == jxl.read.biff.SupbookRecord.INTERNAL) {
      this.type = INTERNAL;
      this.numSheets = sr.getNumberOfSheets();
    } else if (sr.getType() == jxl.read.biff.SupbookRecord.EXTERNAL) {
      this.type = EXTERNAL;
      this.numSheets = sr.getNumberOfSheets();
      this.fileName = sr.getFileName();
      this.sheetNames = new String[this.numSheets];
      for (int i = 0; i < this.numSheets; i++)
        this.sheetNames[i] = sr.getSheetName(i); 
    } 
  }
  
  private void initInternal(jxl.read.biff.SupbookRecord sr) {
    this.numSheets = sr.getNumberOfSheets();
    initInternal();
  }
  
  private void initInternal() {
    this.data = new byte[4];
    IntegerHelper.getTwoBytes(this.numSheets, this.data, 0);
    this.data[2] = 1;
    this.data[3] = 4;
    this.type = INTERNAL;
  }
  
  void adjustInternal(int sheets) {
    Assert.verify((this.type == INTERNAL));
    this.numSheets = sheets;
    initInternal();
  }
  
  private void initExternal() {
    int totalSheetNameLength = 0;
    for (int i = 0; i < this.numSheets; i++)
      totalSheetNameLength += this.sheetNames[i].length(); 
    byte[] fileNameData = EncodedURLHelper.getEncodedURL(this.fileName, this.workbookSettings);
    int dataLength = 6 + fileNameData.length + this.numSheets * 3 + totalSheetNameLength * 2;
    this.data = new byte[dataLength];
    IntegerHelper.getTwoBytes(this.numSheets, this.data, 0);
    int pos = 2;
    IntegerHelper.getTwoBytes(fileNameData.length + 1, this.data, pos);
    this.data[pos + 2] = 0;
    this.data[pos + 3] = 1;
    System.arraycopy(fileNameData, 0, this.data, pos + 4, fileNameData.length);
    pos += 4 + fileNameData.length;
    for (int j = 0; j < this.sheetNames.length; j++) {
      IntegerHelper.getTwoBytes(this.sheetNames[j].length(), this.data, pos);
      this.data[pos + 2] = 1;
      StringHelper.getUnicodeBytes(this.sheetNames[j], this.data, pos + 3);
      pos += 3 + this.sheetNames[j].length() * 2;
    } 
  }
  
  public byte[] getData() {
    if (this.type == INTERNAL) {
      initInternal();
    } else if (this.type == EXTERNAL) {
      initExternal();
    } else {
      logger.warn("unsupported supbook type - defaulting to internal");
      initInternal();
    } 
    return this.data;
  }
  
  public SupbookType getType() {
    return this.type;
  }
  
  public int getNumberOfSheets() {
    return this.numSheets;
  }
  
  public String getFileName() {
    return this.fileName;
  }
  
  public int getSheetIndex(String s) {
    boolean found = false;
    int sheetIndex = 0;
    for (int i = 0; i < this.sheetNames.length && !found; i++) {
      if (this.sheetNames[i].equals(s)) {
        found = true;
        sheetIndex = 0;
      } 
    } 
    if (found)
      return sheetIndex; 
    String[] names = new String[this.sheetNames.length + 1];
    names[this.sheetNames.length] = s;
    this.sheetNames = names;
    return this.sheetNames.length - 1;
  }
  
  public String getSheetName(int s) {
    return this.sheetNames[s];
  }
}
