package jxl.biff;

import common.Assert;
import common.Logger;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import jxl.WorkbookSettings;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.CellFormat;
import jxl.format.Colour;
import jxl.format.Font;
import jxl.format.Format;
import jxl.format.Orientation;
import jxl.format.Pattern;
import jxl.format.VerticalAlignment;
import jxl.read.biff.Record;

public class XFRecord extends WritableRecordData implements CellFormat {
  private static Logger logger = Logger.getLogger(XFRecord.class);
  
  public int formatIndex;
  
  private int parentFormat;
  
  private XFType xfFormatType;
  
  private boolean date;
  
  private boolean number;
  
  private DateFormat dateFormat;
  
  private NumberFormat numberFormat;
  
  private byte usedAttributes;
  
  private int fontIndex;
  
  private boolean locked;
  
  private boolean hidden;
  
  private Alignment align;
  
  private VerticalAlignment valign;
  
  private Orientation orientation;
  
  private boolean wrap;
  
  private int indentation;
  
  private boolean shrinkToFit;
  
  private BorderLineStyle leftBorder;
  
  private BorderLineStyle rightBorder;
  
  private BorderLineStyle topBorder;
  
  private BorderLineStyle bottomBorder;
  
  private Colour leftBorderColour;
  
  private Colour rightBorderColour;
  
  private Colour topBorderColour;
  
  private Colour bottomBorderColour;
  
  private Colour backgroundColour;
  
  private Pattern pattern;
  
  private int options;
  
  private int xfIndex;
  
  private FontRecord font;
  
  private DisplayFormat format;
  
  private boolean initialized;
  
  private boolean read;
  
  private Format excelFormat;
  
  private boolean formatInfoInitialized;
  
  private boolean copied;
  
  private FormattingRecords formattingRecords;
  
  private static final int[] dateFormats = new int[] { 
      14, 15, 16, 17, 18, 19, 20, 21, 22, 45, 
      46, 47 };
  
  private static final DateFormat[] javaDateFormats = new DateFormat[] { 
      new SimpleDateFormat("dd/MM/yyyy"), new SimpleDateFormat("d-MMM-yy"), new SimpleDateFormat("d-MMM"), new SimpleDateFormat("MMM-yy"), new SimpleDateFormat("h:mm a"), new SimpleDateFormat("h:mm:ss a"), new SimpleDateFormat("H:mm"), new SimpleDateFormat("H:mm:ss"), new SimpleDateFormat("M/d/yy H:mm"), new SimpleDateFormat("mm:ss"), 
      new SimpleDateFormat("H:mm:ss"), new SimpleDateFormat("mm:ss.S") };
  
  private static int[] numberFormats = new int[] { 
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
      11, 37, 38, 39, 40, 41, 42, 43, 44, 48 };
  
  private static NumberFormat[] javaNumberFormats = new NumberFormat[] { 
      new DecimalFormat("0"), new DecimalFormat("0.00"), new DecimalFormat("#,##0"), new DecimalFormat("#,##0.00"), new DecimalFormat("$#,##0;($#,##0)"), new DecimalFormat("$#,##0;($#,##0)"), new DecimalFormat("$#,##0.00;($#,##0.00)"), new DecimalFormat("$#,##0.00;($#,##0.00)"), new DecimalFormat("0%"), new DecimalFormat("0.00%"), 
      new DecimalFormat("0.00E00"), new DecimalFormat("#,##0;(#,##0)"), new DecimalFormat("#,##0;(#,##0)"), new DecimalFormat("#,##0.00;(#,##0.00)"), new DecimalFormat("#,##0.00;(#,##0.00)"), new DecimalFormat("#,##0;(#,##0)"), new DecimalFormat("$#,##0;($#,##0)"), new DecimalFormat("#,##0.00;(#,##0.00)"), new DecimalFormat("$#,##0.00;($#,##0.00)"), new DecimalFormat("##0.0E0") };
  
  private static class BiffType {
    private BiffType() {}
  }
  
  public static final BiffType biff8 = new BiffType();
  
  public static final BiffType biff7 = new BiffType();
  
  private BiffType biffType;
  
  private static class XFType {
    private XFType() {}
  }
  
  protected static final XFType cell = new XFType();
  
  protected static final XFType style = new XFType();
  
  public XFRecord(Record t, WorkbookSettings ws, BiffType bt) {
    super(t);
    this.biffType = bt;
    byte[] data = getRecord().getData();
    this.fontIndex = IntegerHelper.getInt(data[0], data[1]);
    this.formatIndex = IntegerHelper.getInt(data[2], data[3]);
    this.date = false;
    this.number = false;
    int i;
    for (i = 0; i < dateFormats.length && !this.date; i++) {
      if (this.formatIndex == dateFormats[i]) {
        this.date = true;
        this.dateFormat = javaDateFormats[i];
      } 
    } 
    for (i = 0; i < numberFormats.length && !this.number; i++) {
      if (this.formatIndex == numberFormats[i]) {
        this.number = true;
        DecimalFormat df = (DecimalFormat)javaNumberFormats[i].clone();
        DecimalFormatSymbols symbols = new DecimalFormatSymbols(ws.getLocale());
        df.setDecimalFormatSymbols(symbols);
        this.numberFormat = df;
      } 
    } 
    int cellAttributes = IntegerHelper.getInt(data[4], data[5]);
    this.parentFormat = (cellAttributes & 0xFFF0) >> 4;
    int formatType = cellAttributes & 0x4;
    this.xfFormatType = (formatType == 0) ? cell : style;
    this.locked = ((cellAttributes & 0x1) != 0);
    this.hidden = ((cellAttributes & 0x2) != 0);
    if (this.xfFormatType == cell && (this.parentFormat & 0xFFF) == 4095) {
      this.parentFormat = 0;
      logger.warn("Invalid parent format found - ignoring");
    } 
    this.initialized = false;
    this.read = true;
    this.formatInfoInitialized = false;
    this.copied = false;
  }
  
  public XFRecord(FontRecord fnt, DisplayFormat form) {
    super(Type.XF);
    this.initialized = false;
    this.locked = true;
    this.hidden = false;
    this.align = Alignment.GENERAL;
    this.valign = VerticalAlignment.BOTTOM;
    this.orientation = Orientation.HORIZONTAL;
    this.wrap = false;
    this.leftBorder = BorderLineStyle.NONE;
    this.rightBorder = BorderLineStyle.NONE;
    this.topBorder = BorderLineStyle.NONE;
    this.bottomBorder = BorderLineStyle.NONE;
    this.leftBorderColour = Colour.AUTOMATIC;
    this.rightBorderColour = Colour.AUTOMATIC;
    this.topBorderColour = Colour.AUTOMATIC;
    this.bottomBorderColour = Colour.AUTOMATIC;
    this.pattern = Pattern.NONE;
    this.backgroundColour = Colour.DEFAULT_BACKGROUND;
    this.indentation = 0;
    this.shrinkToFit = false;
    this.parentFormat = 0;
    this.xfFormatType = null;
    this.font = fnt;
    this.format = form;
    this.biffType = biff8;
    this.read = false;
    this.copied = false;
    this.formatInfoInitialized = true;
    Assert.verify((this.font != null));
    Assert.verify((this.format != null));
  }
  
  protected XFRecord(XFRecord fmt) {
    super(Type.XF);
    this.initialized = false;
    this.locked = fmt.locked;
    this.hidden = fmt.hidden;
    this.align = fmt.align;
    this.valign = fmt.valign;
    this.orientation = fmt.orientation;
    this.wrap = fmt.wrap;
    this.leftBorder = fmt.leftBorder;
    this.rightBorder = fmt.rightBorder;
    this.topBorder = fmt.topBorder;
    this.bottomBorder = fmt.bottomBorder;
    this.leftBorderColour = fmt.leftBorderColour;
    this.rightBorderColour = fmt.rightBorderColour;
    this.topBorderColour = fmt.topBorderColour;
    this.bottomBorderColour = fmt.bottomBorderColour;
    this.pattern = fmt.pattern;
    this.xfFormatType = fmt.xfFormatType;
    this.indentation = fmt.indentation;
    this.shrinkToFit = fmt.shrinkToFit;
    this.parentFormat = fmt.parentFormat;
    this.backgroundColour = fmt.backgroundColour;
    this.font = fmt.font;
    this.format = fmt.format;
    this.fontIndex = fmt.fontIndex;
    this.formatIndex = fmt.formatIndex;
    this.formatInfoInitialized = fmt.formatInfoInitialized;
    this.biffType = biff8;
    this.read = false;
    this.copied = true;
  }
  
  protected XFRecord(CellFormat cellFormat) {
    super(Type.XF);
    Assert.verify((cellFormat != null));
    Assert.verify(cellFormat instanceof XFRecord);
    XFRecord fmt = (XFRecord)cellFormat;
    if (!fmt.formatInfoInitialized)
      fmt.initializeFormatInformation(); 
    this.locked = fmt.locked;
    this.hidden = fmt.hidden;
    this.align = fmt.align;
    this.valign = fmt.valign;
    this.orientation = fmt.orientation;
    this.wrap = fmt.wrap;
    this.leftBorder = fmt.leftBorder;
    this.rightBorder = fmt.rightBorder;
    this.topBorder = fmt.topBorder;
    this.bottomBorder = fmt.bottomBorder;
    this.leftBorderColour = fmt.leftBorderColour;
    this.rightBorderColour = fmt.rightBorderColour;
    this.topBorderColour = fmt.topBorderColour;
    this.bottomBorderColour = fmt.bottomBorderColour;
    this.pattern = fmt.pattern;
    this.xfFormatType = fmt.xfFormatType;
    this.parentFormat = fmt.parentFormat;
    this.indentation = fmt.indentation;
    this.shrinkToFit = fmt.shrinkToFit;
    this.backgroundColour = fmt.backgroundColour;
    this.font = new FontRecord(fmt.getFont());
    if (fmt.getFormat() == null) {
      if (fmt.format.isBuiltIn()) {
        this.format = fmt.format;
      } else {
        this.format = new FormatRecord((FormatRecord)fmt.format);
      } 
    } else if (fmt.getFormat() instanceof BuiltInFormat) {
      this.excelFormat = fmt.excelFormat;
      this.format = (BuiltInFormat)fmt.excelFormat;
    } else {
      Assert.verify(fmt.formatInfoInitialized);
      Assert.verify(fmt.excelFormat instanceof FormatRecord);
      FormatRecord fr = new FormatRecord((FormatRecord)fmt.excelFormat);
      this.excelFormat = fr;
      this.format = fr;
    } 
    this.biffType = biff8;
    this.formatInfoInitialized = true;
    this.read = false;
    this.copied = false;
    this.initialized = false;
  }
  
  public DateFormat getDateFormat() {
    return this.dateFormat;
  }
  
  public NumberFormat getNumberFormat() {
    return this.numberFormat;
  }
  
  public int getFormatRecord() {
    return this.formatIndex;
  }
  
  public boolean isDate() {
    return this.date;
  }
  
  public boolean isNumber() {
    return this.number;
  }
  
  public byte[] getData() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    byte[] data = new byte[20];
    IntegerHelper.getTwoBytes(this.fontIndex, data, 0);
    IntegerHelper.getTwoBytes(this.formatIndex, data, 2);
    int cellAttributes = 0;
    if (getLocked())
      cellAttributes |= 0x1; 
    if (getHidden())
      cellAttributes |= 0x2; 
    if (this.xfFormatType == style) {
      cellAttributes |= 0x4;
      this.parentFormat = 65535;
    } 
    cellAttributes |= this.parentFormat << 4;
    IntegerHelper.getTwoBytes(cellAttributes, data, 4);
    int alignMask = this.align.getValue();
    if (this.wrap)
      alignMask |= 0x8; 
    alignMask |= this.valign.getValue() << 4;
    alignMask |= this.orientation.getValue() << 8;
    IntegerHelper.getTwoBytes(alignMask, data, 6);
    data[9] = 16;
    int borderMask = this.leftBorder.getValue();
    borderMask |= this.rightBorder.getValue() << 4;
    borderMask |= this.topBorder.getValue() << 8;
    borderMask |= this.bottomBorder.getValue() << 12;
    IntegerHelper.getTwoBytes(borderMask, data, 10);
    if (borderMask != 0) {
      byte lc = (byte)this.leftBorderColour.getValue();
      byte rc = (byte)this.rightBorderColour.getValue();
      byte tc = (byte)this.topBorderColour.getValue();
      byte bc = (byte)this.bottomBorderColour.getValue();
      int sideColourMask = lc & Byte.MAX_VALUE | (rc & Byte.MAX_VALUE) << 7;
      int topColourMask = tc & Byte.MAX_VALUE | (bc & Byte.MAX_VALUE) << 7;
      IntegerHelper.getTwoBytes(sideColourMask, data, 12);
      IntegerHelper.getTwoBytes(topColourMask, data, 14);
    } 
    int patternVal = this.pattern.getValue() << 10;
    IntegerHelper.getTwoBytes(patternVal, data, 16);
    int colourPaletteMask = this.backgroundColour.getValue();
    colourPaletteMask |= 0x2000;
    IntegerHelper.getTwoBytes(colourPaletteMask, data, 18);
    this.options |= this.indentation & 0xF;
    if (this.shrinkToFit) {
      this.options |= 0x10;
    } else {
      this.options &= 0xEF;
    } 
    data[8] = (byte)this.options;
    if (this.biffType == biff8)
      data[9] = this.usedAttributes; 
    return data;
  }
  
  protected final boolean getLocked() {
    return this.locked;
  }
  
  protected final boolean getHidden() {
    return this.hidden;
  }
  
  protected final void setXFLocked(boolean l) {
    this.locked = l;
  }
  
  protected final void setXFCellOptions(int opt) {
    this.options |= opt;
  }
  
  protected void setXFAlignment(Alignment a) {
    Assert.verify(!this.initialized);
    this.align = a;
  }
  
  protected void setXFIndentation(int i) {
    Assert.verify(!this.initialized);
    this.indentation = i;
  }
  
  protected void setXFShrinkToFit(boolean s) {
    Assert.verify(!this.initialized);
    this.shrinkToFit = s;
  }
  
  public Alignment getAlignment() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.align;
  }
  
  public int getIndentation() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.indentation;
  }
  
  public boolean isShrinkToFit() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.shrinkToFit;
  }
  
  public boolean isLocked() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.locked;
  }
  
  public VerticalAlignment getVerticalAlignment() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.valign;
  }
  
  public Orientation getOrientation() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.orientation;
  }
  
  protected void setXFBackground(Colour c, Pattern p) {
    Assert.verify(!this.initialized);
    this.backgroundColour = c;
    this.pattern = p;
  }
  
  public Colour getBackgroundColour() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.backgroundColour;
  }
  
  public Pattern getPattern() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.pattern;
  }
  
  protected void setXFVerticalAlignment(VerticalAlignment va) {
    Assert.verify(!this.initialized);
    this.valign = va;
  }
  
  protected void setXFOrientation(Orientation o) {
    Assert.verify(!this.initialized);
    this.orientation = o;
  }
  
  protected void setXFWrap(boolean w) {
    Assert.verify(!this.initialized);
    this.wrap = w;
  }
  
  public boolean getWrap() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.wrap;
  }
  
  protected void setXFBorder(Border b, BorderLineStyle ls, Colour c) {
    Assert.verify(!this.initialized);
    if (c == Colour.BLACK)
      c = Colour.PALETTE_BLACK; 
    if (b == Border.LEFT) {
      this.leftBorder = ls;
      this.leftBorderColour = c;
    } else if (b == Border.RIGHT) {
      this.rightBorder = ls;
      this.rightBorderColour = c;
    } else if (b == Border.TOP) {
      this.topBorder = ls;
      this.topBorderColour = c;
    } else if (b == Border.BOTTOM) {
      this.bottomBorder = ls;
      this.bottomBorderColour = c;
    } 
  }
  
  public BorderLineStyle getBorder(Border border) {
    return getBorderLine(border);
  }
  
  public BorderLineStyle getBorderLine(Border border) {
    if (border == Border.NONE || border == Border.ALL)
      return BorderLineStyle.NONE; 
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    if (border == Border.LEFT)
      return this.leftBorder; 
    if (border == Border.RIGHT)
      return this.rightBorder; 
    if (border == Border.TOP)
      return this.topBorder; 
    if (border == Border.BOTTOM)
      return this.bottomBorder; 
    return BorderLineStyle.NONE;
  }
  
  public Colour getBorderColour(Border border) {
    if (border == Border.NONE || border == Border.ALL)
      return Colour.PALETTE_BLACK; 
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    if (border == Border.LEFT)
      return this.leftBorderColour; 
    if (border == Border.RIGHT)
      return this.rightBorderColour; 
    if (border == Border.TOP)
      return this.topBorderColour; 
    if (border == Border.BOTTOM)
      return this.bottomBorderColour; 
    return Colour.BLACK;
  }
  
  public final boolean hasBorders() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    if (this.leftBorder == BorderLineStyle.NONE && this.rightBorder == BorderLineStyle.NONE && this.topBorder == BorderLineStyle.NONE && this.bottomBorder == BorderLineStyle.NONE)
      return false; 
    return true;
  }
  
  public final void initialize(int pos, FormattingRecords fr, Fonts fonts) throws NumFormatRecordsException {
    this.xfIndex = pos;
    this.formattingRecords = fr;
    if (this.read || this.copied) {
      this.initialized = true;
      return;
    } 
    if (!this.font.isInitialized())
      fonts.addFont(this.font); 
    if (!this.format.isInitialized())
      fr.addFormat(this.format); 
    this.fontIndex = this.font.getFontIndex();
    this.formatIndex = this.format.getFormatIndex();
    this.initialized = true;
  }
  
  public final void uninitialize() {
    if (this.initialized == true)
      logger.warn("A default format has been initialized"); 
    this.initialized = false;
  }
  
  final void setXFIndex(int xfi) {
    this.xfIndex = xfi;
  }
  
  public final int getXFIndex() {
    return this.xfIndex;
  }
  
  public final boolean isInitialized() {
    return this.initialized;
  }
  
  public final boolean isRead() {
    return this.read;
  }
  
  public Format getFormat() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.excelFormat;
  }
  
  public Font getFont() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    return this.font;
  }
  
  private void initializeFormatInformation() {
    if (this.formatIndex < BuiltInFormat.builtIns.length && BuiltInFormat.builtIns[this.formatIndex] != null) {
      this.excelFormat = BuiltInFormat.builtIns[this.formatIndex];
    } else {
      this.excelFormat = this.formattingRecords.getFormatRecord(this.formatIndex);
    } 
    this.font = this.formattingRecords.getFonts().getFont(this.fontIndex);
    byte[] data = getRecord().getData();
    int cellAttributes = IntegerHelper.getInt(data[4], data[5]);
    this.parentFormat = (cellAttributes & 0xFFF0) >> 4;
    int formatType = cellAttributes & 0x4;
    this.xfFormatType = (formatType == 0) ? cell : style;
    this.locked = ((cellAttributes & 0x1) != 0);
    this.hidden = ((cellAttributes & 0x2) != 0);
    if (this.xfFormatType == cell && (this.parentFormat & 0xFFF) == 4095) {
      this.parentFormat = 0;
      logger.warn("Invalid parent format found - ignoring");
    } 
    int alignMask = IntegerHelper.getInt(data[6], data[7]);
    if ((alignMask & 0x8) != 0)
      this.wrap = true; 
    this.align = Alignment.getAlignment(alignMask & 0x7);
    this.valign = VerticalAlignment.getAlignment(alignMask >> 4 & 0x7);
    this.orientation = Orientation.getOrientation(alignMask >> 8 & 0xFF);
    int attr = IntegerHelper.getInt(data[8], data[9]);
    this.indentation = attr & 0xF;
    this.shrinkToFit = ((attr & 0x10) != 0);
    if (this.biffType == biff8)
      this.usedAttributes = data[9]; 
    int borderMask = IntegerHelper.getInt(data[10], data[11]);
    this.leftBorder = BorderLineStyle.getStyle(borderMask & 0x7);
    this.rightBorder = BorderLineStyle.getStyle(borderMask >> 4 & 0x7);
    this.topBorder = BorderLineStyle.getStyle(borderMask >> 8 & 0x7);
    this.bottomBorder = BorderLineStyle.getStyle(borderMask >> 12 & 0x7);
    int borderColourMask = IntegerHelper.getInt(data[12], data[13]);
    this.leftBorderColour = Colour.getInternalColour(borderColourMask & 0x7F);
    this.rightBorderColour = Colour.getInternalColour((borderColourMask & 0x3F80) >> 7);
    borderColourMask = IntegerHelper.getInt(data[14], data[15]);
    this.topBorderColour = Colour.getInternalColour(borderColourMask & 0x7F);
    this.bottomBorderColour = Colour.getInternalColour((borderColourMask & 0x3F80) >> 7);
    if (this.biffType == biff8) {
      int patternVal = IntegerHelper.getInt(data[16], data[17]);
      patternVal &= 0xFC00;
      patternVal >>= 10;
      this.pattern = Pattern.getPattern(patternVal);
      int colourPaletteMask = IntegerHelper.getInt(data[18], data[19]);
      this.backgroundColour = Colour.getInternalColour(colourPaletteMask & 0x3F);
      if (this.backgroundColour == Colour.UNKNOWN || this.backgroundColour == Colour.DEFAULT_BACKGROUND1)
        this.backgroundColour = Colour.DEFAULT_BACKGROUND; 
    } else {
      this.pattern = Pattern.NONE;
      this.backgroundColour = Colour.DEFAULT_BACKGROUND;
    } 
    this.formatInfoInitialized = true;
  }
  
  public int hashCode() {
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    int hashValue = 17;
    int oddPrimeNumber = 37;
    hashValue = oddPrimeNumber * hashValue + (this.hidden ? 1 : 0);
    hashValue = oddPrimeNumber * hashValue + (this.locked ? 1 : 0);
    hashValue = oddPrimeNumber * hashValue + (this.wrap ? 1 : 0);
    hashValue = oddPrimeNumber * hashValue + (this.shrinkToFit ? 1 : 0);
    if (this.xfFormatType == cell) {
      hashValue = oddPrimeNumber * hashValue + 1;
    } else if (this.xfFormatType == style) {
      hashValue = oddPrimeNumber * hashValue + 2;
    } 
    hashValue = oddPrimeNumber * hashValue + this.align.getValue() + 1;
    hashValue = oddPrimeNumber * hashValue + this.valign.getValue() + 1;
    hashValue = oddPrimeNumber * hashValue + this.orientation.getValue();
    hashValue ^= this.leftBorder.getDescription().hashCode();
    hashValue ^= this.rightBorder.getDescription().hashCode();
    hashValue ^= this.topBorder.getDescription().hashCode();
    hashValue ^= this.bottomBorder.getDescription().hashCode();
    hashValue = oddPrimeNumber * hashValue + this.leftBorderColour.getValue();
    hashValue = oddPrimeNumber * hashValue + this.rightBorderColour.getValue();
    hashValue = oddPrimeNumber * hashValue + this.topBorderColour.getValue();
    hashValue = oddPrimeNumber * hashValue + this.bottomBorderColour.getValue();
    hashValue = oddPrimeNumber * hashValue + this.backgroundColour.getValue();
    hashValue = oddPrimeNumber * hashValue + this.pattern.getValue() + 1;
    hashValue = oddPrimeNumber * hashValue + this.usedAttributes;
    hashValue = oddPrimeNumber * hashValue + this.parentFormat;
    hashValue = oddPrimeNumber * hashValue + this.fontIndex;
    hashValue = oddPrimeNumber * hashValue + this.formatIndex;
    hashValue = oddPrimeNumber * hashValue + this.indentation;
    return hashValue;
  }
  
  public boolean equals(Object o) {
    if (o == this)
      return true; 
    if (!(o instanceof XFRecord))
      return false; 
    XFRecord xfr = (XFRecord)o;
    if (!this.formatInfoInitialized)
      initializeFormatInformation(); 
    if (!xfr.formatInfoInitialized)
      xfr.initializeFormatInformation(); 
    if (this.xfFormatType != xfr.xfFormatType || this.parentFormat != xfr.parentFormat || this.locked != xfr.locked || this.hidden != xfr.hidden || this.usedAttributes != xfr.usedAttributes)
      return false; 
    if (this.align != xfr.align || this.valign != xfr.valign || this.orientation != xfr.orientation || this.wrap != xfr.wrap || this.shrinkToFit != xfr.shrinkToFit || this.indentation != xfr.indentation)
      return false; 
    if (this.leftBorder != xfr.leftBorder || this.rightBorder != xfr.rightBorder || this.topBorder != xfr.topBorder || this.bottomBorder != xfr.bottomBorder)
      return false; 
    if (this.leftBorderColour != xfr.leftBorderColour || this.rightBorderColour != xfr.rightBorderColour || this.topBorderColour != xfr.topBorderColour || this.bottomBorderColour != xfr.bottomBorderColour)
      return false; 
    if (this.backgroundColour != xfr.backgroundColour || this.pattern != xfr.pattern)
      return false; 
    if (this.initialized && xfr.initialized) {
      if (this.fontIndex != xfr.fontIndex || this.formatIndex != xfr.formatIndex)
        return false; 
    } else if (!this.font.equals(xfr.font) || !this.format.equals(xfr.format)) {
      return false;
    } 
    return true;
  }
  
  void setFormatIndex(int newindex) {
    this.formatIndex = newindex;
  }
  
  int getFontIndex() {
    return this.fontIndex;
  }
  
  void setFontIndex(int newindex) {
    this.fontIndex = newindex;
  }
  
  protected void setXFDetails(XFType t, int pf) {
    this.xfFormatType = t;
    this.parentFormat = pf;
  }
  
  void rationalize(IndexMapping xfMapping) {
    this.xfIndex = xfMapping.getNewIndex(this.xfIndex);
    if (this.xfFormatType == cell)
      this.parentFormat = xfMapping.getNewIndex(this.parentFormat); 
  }
  
  public void setFont(FontRecord f) {
    this.font = f;
  }
}
