/**
         * Gets the external sheet index for the sheet name
         *
         * @param sheetName
         * @return the sheet index or -1 if the sheet could not be found
         */
        public int getExternalSheetIndex(string sheetName)
        {
            if (externSheet == null)
                {
                externSheet = new ExternalSheetRecord();
                supbooks = new ArrayList();
                supbooks.Add(new SupbookRecord(getNumberOfSheets(), settings));
                }

            // Iterate through the sheets records
            bool found = false;
            int sheetpos = 0;

            foreach (WritableSheetImpl s in sheets)
                {
                if (s.getName() == sheetName)
                    {
                    found = true;
                    break;
                    }
                else
                    sheetpos++;
                }

            if (found)
                {
                // Check that the supbook record at position zero is internal and
                // contains all the sheets
            // if (supbooks.Count > 0)		// CML -- was this an advertent bug?
                SupbookRecord supbook = (SupbookRecord)supbooks[0];
                if (supbook.getType() != SupbookRecord.INTERNAL || supbook.getNumberOfSheets() != getNumberOfSheets())
                    {
                    //logger.warn("Cannot find sheet " + sheetName + " in supbook record");
                    }
                return externSheet.getIndex(0, sheetpos);
                }

            // Check for square brackets
            int closeSquareBracketsIndex = sheetName.LastIndexOf(']');
            int openSquareBracketsIndex = sheetName.LastIndexOf('[');

            if (closeSquareBracketsIndex == -1 ||
                openSquareBracketsIndex == -1)
                {
                //logger.warn("Square brackets");
                return -1;
                }

            string worksheetName = sheetName.Substring(closeSquareBracketsIndex + 1);
            string workbookName = sheetName.Substring(openSquareBracketsIndex + 1,closeSquareBracketsIndex);
            string path = sheetName.Substring(0, openSquareBracketsIndex);
            string fileName = path + workbookName;

            bool supbookFound = false;
            SupbookRecord externalSupbook = null;
            int supbookIndex = -1;
            for (int ind = 0; ind < supbooks.Count && !supbookFound; ind++)
                {
                externalSupbook = (SupbookRecord)supbooks[ind];
                if (externalSupbook.getType() == SupbookRecord.EXTERNAL &&
                    externalSupbook.getFileName().Equals(fileName))
                    {
                    supbookFound = true;
                    supbookIndex = ind;
                    }
                }

            if (!supbookFound)
                {
                externalSupbook = new SupbookRecord(fileName, settings);
                supbookIndex = supbooks.Count;
                supbooks.Add(externalSupbook);
                }

            int sheetIndex = externalSupbook.getSheetIndex(worksheetName);

            return externSheet.getIndex(supbookIndex, sheetIndex);
        }
        /**
         * Gets the last external sheet index for the sheet name
         * @param sheetName
         * @return the sheet index or -1 if the sheet could not be found
         */
        public int getLastExternalSheetIndex(string sheetName)
        {
            if (externSheet == null)
                {
                externSheet = new ExternalSheetRecord();
                supbooks = new ArrayList();
                supbooks.Add(new SupbookRecord(getNumberOfSheets(), settings));
                }

            // Iterate through the sheets records
            bool found = false;
            int sheetpos = 0;
            foreach (WritableSheetImpl s in sheets)
                {
                if (found)
                    break;

                if (s.getName().Equals(sheetName))
                    found = true;
                else
                    sheetpos++;
                }

            if (!found
                || supbooks.Count > 0)		// CML -- was this an advertent bug?
                return -1;

            // Check that the supbook record at position zero is internal and contains
            // all the sheets
            SupbookRecord supbook = (SupbookRecord)supbooks[0];
            Assert.verify(supbook.getType() == SupbookRecord.INTERNAL &&
                          supbook.getNumberOfSheets() == getNumberOfSheets());

            return externSheet.getIndex(0, sheetpos);
        }
        /**
         * A pseudo copy constructor.  Takes the handles to the font and formatting
         * records
         *
         * @exception IOException
         * @param w the workbook to copy
         * @param os the output stream to write the data to
         * @param cs TRUE if the workbook should close the output stream, FALSE
         * @param ws the configuration for this workbook
         */
        public WritableWorkbookImpl(Stream os,
            Workbook w,
            bool cs,
            WorkbookSettings ws)
            : base()
        {
            CSharpJExcel.Jxl.Read.Biff.WorkbookParser wp = (CSharpJExcel.Jxl.Read.Biff.WorkbookParser)w;

            // Reset the statically declared styles.  These are no longer needed
            // because the Styles class will intercept all calls within
            // CellValue.setCellDetails and if it detects a standard format, then it
            // will return a clone.  In short, the static cell values will
            // never get initialized anyway.  Still, just to be extra sure...
            //lock (SYNCHRONIZER)
            //    {
            //    WritableWorkbook.ARIAL_10_PT.uninitialize();
            //    WritableWorkbook.HYPERLINK_FONT.uninitialize();
            //    WritableWorkbook.NORMAL_STYLE.uninitialize();
            //    WritableWorkbook.HYPERLINK_STYLE.uninitialize();
            //    WritableWorkbook.HIDDEN_STYLE.uninitialize();
            //    DateRecord.defaultDateFormat.uninitialize();
            //    }

            closeStream = cs;
            sheets = new ArrayList();
            sharedStrings = new SharedStrings();
            nameRecords = new Dictionary<string, NameRecord>();
            fonts = wp.getFonts();
            formatRecords = wp.getFormattingRecords();
            wbProtected = false;
            settings = ws;
            rcirCells = new ArrayList();
            styles = new Styles();
            outputFile = new File(os, ws, wp.getCompoundFile());

            containsMacros = false;
            if (!ws.getPropertySetsDisabled())
                containsMacros = wp.containsMacros();

            // Copy the country settings
            if (wp.getCountryRecord() != null)
                countryRecord = new CountryRecord(wp.getCountryRecord());

            // Copy any add in functions
            addInFunctionNames = wp.getAddInFunctionNames();

            // Copy XCT records
            xctRecords = wp.getXCTRecords();

            // Copy any external sheets
            if (wp.getExternalSheetRecord() != null)
                {
                externSheet = new ExternalSheetRecord(wp.getExternalSheetRecord());

                // Get the associated supbooks
                CSharpJExcel.Jxl.Read.Biff.SupbookRecord[] readsr = wp.getSupbookRecords();
                supbooks = new ArrayList(readsr.Length);

                for (int i = 0; i < readsr.Length; i++)
                    {
                    CSharpJExcel.Jxl.Read.Biff.SupbookRecord readSupbook = readsr[i];
                    if (readSupbook.getType() == SupbookRecord.INTERNAL || readSupbook.getType() == SupbookRecord.EXTERNAL)
                        supbooks.Add(new SupbookRecord(readSupbook, settings));
                    else
                        {
                        if (readSupbook.getType() != SupbookRecord.ADDIN)
                            {
                            //logger.warn("unsupported supbook type - ignoring");
                            }
                        }
                    }
                }

            // Copy any drawings.  These must be present before we try and copy
            // the images from the read workbook
            if (wp.getDrawingGroup() != null)
                drawingGroup = new DrawingGroup(wp.getDrawingGroup());

            // Copy the property set references
            if (containsMacros && wp.getButtonPropertySet() != null)
                buttonPropertySet = new ButtonPropertySetRecord(wp.getButtonPropertySet());

            // Copy any names
            if (!settings.getNamesDisabled())
                {
                CSharpJExcel.Jxl.Read.Biff.NameRecord[] na = wp.getNameRecords();
                names = new ArrayList(na.Length);

                for (int i = 0; i < na.Length; i++)
                    {
                    if (na[i].isBiff8())
                        {
                        NameRecord n = new NameRecord(na[i], i);
                        names.Add(n);
                        string key = n.getName() == null ? NULLKEY : n.getName();
                        nameRecords.Add(key, n);
                        }
                    else
                        {
                        //logger.warn("Cannot copy Biff7 name records - ignoring");
                        }
                    }
                }

            copyWorkbook(w);

            // The copy process may have caused some critical fields in the
            // read drawing group to change.  Make sure these updates are reflected
            // in the writable drawing group
            if (drawingGroup != null)
                drawingGroup.updateData(wp.getDrawingGroup());
        }