/* ====================================================================
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
==================================================================== */

package org.zkoss.poi.hssf.usermodel;

import org.zkoss.poi.hssf.record.CFRuleRecord;
import org.zkoss.poi.hssf.record.aggregates.CFRecordsAggregate;
import org.zkoss.poi.hssf.record.aggregates.ConditionalFormattingTable;
import org.zkoss.poi.ss.usermodel.ConditionalFormatting;
import org.zkoss.poi.ss.usermodel.ConditionalFormattingRule;
import org.zkoss.poi.ss.usermodel.SheetConditionalFormatting;
import org.zkoss.poi.ss.util.Region;
import org.zkoss.poi.ss.util.CellRangeAddress;
import org.zkoss.poi.ss.SpreadsheetVersion;

/**
 * The 'Conditional Formatting' facet of <tt>HSSFSheet</tt>
 *
 * @author Dmitriy Kumshayev
 */
public final class HSSFSheetConditionalFormatting implements SheetConditionalFormatting {

	private final HSSFSheet _sheet;
	private final ConditionalFormattingTable _conditionalFormattingTable;

	/* package */ HSSFSheetConditionalFormatting(HSSFSheet sheet) {
		_sheet = sheet;
		_conditionalFormattingTable = sheet.getSheet().getConditionalFormattingTable();
	}

	/**
	 * A factory method allowing to create a conditional formatting rule
	 * with a cell comparison operator<p/>
	 * TODO - formulas containing cell references are currently not parsed properly
	 *
	 * @param comparisonOperation - a constant value from
	 *		 <tt>{@link org.zkoss.poi.hssf.record.CFRuleRecord.ComparisonOperator}</tt>: <p>
	 * <ul>
	 *		 <li>BETWEEN</li>
	 *		 <li>NOT_BETWEEN</li>
	 *		 <li>EQUAL</li>
	 *		 <li>NOT_EQUAL</li>
	 *		 <li>GT</li>
	 *		 <li>LT</li>
	 *		 <li>GE</li>
	 *		 <li>LE</li>
	 * </ul>
	 * </p>
	 * @param formula1 - formula for the valued, compared with the cell
	 * @param formula2 - second formula (only used with
	 * {@link org.zkoss.poi.hssf.record.CFRuleRecord.ComparisonOperator#BETWEEN}) and
	 * {@link org.zkoss.poi.hssf.record.CFRuleRecord.ComparisonOperator#NOT_BETWEEN} operations)
	 */
	public HSSFConditionalFormattingRule createConditionalFormattingRule(
			byte comparisonOperation,
			String formula1,
			String formula2) {

		HSSFWorkbook wb = _sheet.getWorkbook();
		CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, formula2);
		return new HSSFConditionalFormattingRule(wb, rr);
	}

    public HSSFConditionalFormattingRule createConditionalFormattingRule(
            byte comparisonOperation,
            String formula1) {

        HSSFWorkbook wb = _sheet.getWorkbook();
        CFRuleRecord rr = CFRuleRecord.create(_sheet, comparisonOperation, formula1, null);
        return new HSSFConditionalFormattingRule(wb, rr);
    }

	/**
	 * A factory method allowing to create a conditional formatting rule with a formula.<br>
	 *
	 * The formatting rules are applied by Excel when the value of the formula not equal to 0.<p/>
	 * TODO - formulas containing cell references are currently not parsed properly
	 * @param formula - formula for the valued, compared with the cell
	 */
	public HSSFConditionalFormattingRule createConditionalFormattingRule(String formula) {
		HSSFWorkbook wb = _sheet.getWorkbook();
		CFRuleRecord rr = CFRuleRecord.create(_sheet, formula);
		return new HSSFConditionalFormattingRule(wb, rr);
	}

	/**
	 * Adds a copy of HSSFConditionalFormatting object to the sheet
	 * <p>This method could be used to copy HSSFConditionalFormatting object
	 * from one sheet to another. For example:
	 * <pre>
	 * HSSFConditionalFormatting cf = sheet.getConditionalFormattingAt(index);
	 * newSheet.addConditionalFormatting(cf);
	 * </pre>
	 *
	 * @param cf HSSFConditionalFormatting object
	 * @return index of the new Conditional Formatting object
	 */
	public int addConditionalFormatting( HSSFConditionalFormatting cf ) {
		CFRecordsAggregate cfraClone = cf.getCFRecordsAggregate().cloneCFAggregate();

		return _conditionalFormattingTable.add(cfraClone);
	}

    public int addConditionalFormatting( ConditionalFormatting cf ) {
        return addConditionalFormatting((HSSFConditionalFormatting)cf);
    }

	/**
	 * @deprecated use <tt>CellRangeAddress</tt> instead of <tt>Region</tt>
	 */
	public int addConditionalFormatting(org.zkoss.poi.ss.util.Region[] regions, HSSFConditionalFormattingRule[] cfRules) {
		return addConditionalFormatting(org.zkoss.poi.ss.util.Region.convertRegionsToCellRanges(regions), cfRules);
	}
	/**
	 * Allows to add a new Conditional Formatting set to the sheet.
	 *
	 * @param regions - list of rectangular regions to apply conditional formatting rules
	 * @param cfRules - set of up to three conditional formatting rules
	 *
	 * @return index of the newly created Conditional Formatting object
	 */
	public int addConditionalFormatting(CellRangeAddress[] regions, HSSFConditionalFormattingRule[] cfRules) {
		if (regions == null) {
			throw new IllegalArgumentException("regions must not be null");
		}
		for(CellRangeAddress range : regions) range.validate(SpreadsheetVersion.EXCEL97);

		if (cfRules == null) {
			throw new IllegalArgumentException("cfRules must not be null");
		}
		if (cfRules.length == 0) {
			throw new IllegalArgumentException("cfRules must not be empty");
		}
		if (cfRules.length > 3) {
			throw new IllegalArgumentException("Number of rules must not exceed 3");
		}

		CFRuleRecord[] rules = new CFRuleRecord[cfRules.length];
		for (int i = 0; i != cfRules.length; i++) {
			rules[i] = cfRules[i].getCfRuleRecord();
		}
		CFRecordsAggregate cfra = new CFRecordsAggregate(regions, rules);
		return _conditionalFormattingTable.add(cfra);
	}

    public int addConditionalFormatting(CellRangeAddress[] regions, ConditionalFormattingRule[] cfRules) {
        HSSFConditionalFormattingRule[] hfRules;
        if(cfRules instanceof HSSFConditionalFormattingRule[]) hfRules = (HSSFConditionalFormattingRule[])cfRules;
        else {
            hfRules = new HSSFConditionalFormattingRule[cfRules.length];
            System.arraycopy(cfRules, 0, hfRules, 0, hfRules.length);
        }
        return addConditionalFormatting(regions, hfRules);
    }

	public int addConditionalFormatting(CellRangeAddress[] regions,
			HSSFConditionalFormattingRule rule1)
	{
		return addConditionalFormatting(regions,
				rule1 == null ? null : new HSSFConditionalFormattingRule[]
				{
					rule1
				});
	}

    public int addConditionalFormatting(CellRangeAddress[] regions,
            ConditionalFormattingRule rule1)
    {
        return addConditionalFormatting(regions,  (HSSFConditionalFormattingRule)rule1);
    }

	public int addConditionalFormatting(CellRangeAddress[] regions,
			HSSFConditionalFormattingRule rule1,
			HSSFConditionalFormattingRule rule2)
	{
		return addConditionalFormatting(regions,
				new HSSFConditionalFormattingRule[]
				{
						rule1, rule2
				});
	}

    public int addConditionalFormatting(CellRangeAddress[] regions,
            ConditionalFormattingRule rule1,
            ConditionalFormattingRule rule2)
    {
        return addConditionalFormatting(regions,
                (HSSFConditionalFormattingRule)rule1,
                (HSSFConditionalFormattingRule)rule2
                );
    }

	/**
	* gets Conditional Formatting object at a particular index
	*
	* @param index
	*			of the Conditional Formatting object to fetch
	* @return Conditional Formatting object
	*/
	public HSSFConditionalFormatting getConditionalFormattingAt(int index) {
		CFRecordsAggregate cf = _conditionalFormattingTable.get(index);
		if (cf == null) {
			return null;
		}
		return new HSSFConditionalFormatting(_sheet.getWorkbook(), cf);
	}

	/**
	* @return number of Conditional Formatting objects of the sheet
	*/
	public int getNumConditionalFormattings() {
		return _conditionalFormattingTable.size();
	}

	/**
	* removes a Conditional Formatting object by index
	* @param index of a Conditional Formatting object to remove
	*/
	public void removeConditionalFormatting(int index) {
		_conditionalFormattingTable.remove(index);
	}
}
