/* ====================================================================
   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.apache.poi.hssf.record.aggregates;

import java.util.ArrayList;
import java.util.List;

import org.apache.poi.common.Duplicatable;
import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.ColumnInfoRecord;

public final class ColumnInfoRecordsAggregate extends RecordAggregate implements Duplicatable {
	/**
	 * List of {@link ColumnInfoRecord}s assumed to be in order
	 */
	private final List<ColumnInfoRecord> records = new ArrayList<>();

	/**
	 * Creates an empty aggregate
	 */
	public ColumnInfoRecordsAggregate() {}

	public ColumnInfoRecordsAggregate(ColumnInfoRecordsAggregate other) {
		other.records.stream().map(ColumnInfoRecord::copy).forEach(records::add);
	}

	public ColumnInfoRecordsAggregate(RecordStream rs) {
		this();

		boolean isInOrder = true;
		ColumnInfoRecord cirPrev = null;
		while (rs.peekNextClass() == ColumnInfoRecord.class) {
			ColumnInfoRecord cir = (ColumnInfoRecord) rs.getNext();
			records.add(cir);
			if (cirPrev != null && compareColInfos(cirPrev, cir) > 0) {
				isInOrder = false;
			}
			cirPrev = cir;
		}
		if (records.size() < 1) {
			throw new RuntimeException("No column info records found");
		}
		if (!isInOrder) {
			records.sort(ColumnInfoRecordsAggregate::compareColInfos);
		}
	}

	@Override
	public ColumnInfoRecordsAggregate copy() {
		return new ColumnInfoRecordsAggregate(this);
	}

	/**
	 * Inserts a column into the aggregate (at the end of the list).
	 */
	public void insertColumn(ColumnInfoRecord col) {
		records.add(col);
		records.sort(ColumnInfoRecordsAggregate::compareColInfos);
	}

	/**
	 * Inserts a column into the aggregate (at the position specified by
	 * <code>idx</code>.
	 */
	private void insertColumn(int idx, ColumnInfoRecord col) {
		records.add(idx, col);
	}

	/* package */ int getNumColumns() {
		return records.size();
	}

	public void visitContainedRecords(RecordVisitor rv) {
		int nItems = records.size();
		if (nItems < 1) {
			return;
		}
		ColumnInfoRecord cirPrev = null;
		for (ColumnInfoRecord cir : records) {
			rv.visitRecord(cir);
			if (cirPrev != null && compareColInfos(cirPrev, cir) > 0) {
				// Excel probably wouldn't mind, but there is much logic in this class
				// that assumes the column info records are kept in order
				throw new RuntimeException("Column info records are out of order");
			}
			cirPrev = cir;
		}
	}

	private int findStartOfColumnOutlineGroup(int pIdx) {
		// Find the start of the group.
		ColumnInfoRecord columnInfo = records.get(pIdx);
		int level = columnInfo.getOutlineLevel();
		int idx = pIdx;
		while (idx != 0) {
			ColumnInfoRecord prevColumnInfo = records.get(idx - 1);
			if (!prevColumnInfo.isAdjacentBefore(columnInfo)) {
				break;
			}
			if (prevColumnInfo.getOutlineLevel() < level) {
				break;
			}
			idx--;
			columnInfo = prevColumnInfo;
		}

		return idx;
	}

	private int findEndOfColumnOutlineGroup(int colInfoIndex) {
		// Find the end of the group.
		ColumnInfoRecord columnInfo = records.get(colInfoIndex);
		int level = columnInfo.getOutlineLevel();
		int idx = colInfoIndex;
		while (idx < records.size() - 1) {
			ColumnInfoRecord nextColumnInfo = records.get(idx + 1);
			if (!columnInfo.isAdjacentBefore(nextColumnInfo)) {
				break;
			}
			if (nextColumnInfo.getOutlineLevel() < level) {
				break;
			}
			idx++;
			columnInfo = nextColumnInfo;
		}
		return idx;
	}

	private ColumnInfoRecord getColInfo(int idx) {
		return records.get( idx );
	}

	/**
	 * 'Collapsed' state is stored in a single column col info record immediately after the outline group
	 * @param idx
	 * @return true, if the column is collapsed, false otherwise.
	 */
	private boolean isColumnGroupCollapsed(int idx) {
		int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
		int nextColInfoIx = endOfOutlineGroupIdx+1;
		if (nextColInfoIx >= records.size()) {
			return false;
		}
		ColumnInfoRecord nextColInfo = getColInfo(nextColInfoIx);
		if (!getColInfo(endOfOutlineGroupIdx).isAdjacentBefore(nextColInfo)) {
			return false;
		}
		return nextColInfo.getCollapsed();
	}


	private boolean isColumnGroupHiddenByParent(int idx) {
		// Look out outline details of end
		int endLevel = 0;
		boolean endHidden = false;
		int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
		if (endOfOutlineGroupIdx < records.size()) {
			ColumnInfoRecord nextInfo = getColInfo(endOfOutlineGroupIdx + 1);
			if (getColInfo(endOfOutlineGroupIdx).isAdjacentBefore(nextInfo)) {
				endLevel = nextInfo.getOutlineLevel();
				endHidden = nextInfo.getHidden();
			}
		}
		// Look out outline details of start
		int startLevel = 0;
		boolean startHidden = false;
		int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
		if (startOfOutlineGroupIdx > 0) {
			ColumnInfoRecord prevInfo = getColInfo(startOfOutlineGroupIdx - 1);
			if (prevInfo.isAdjacentBefore(getColInfo(startOfOutlineGroupIdx))) {
				startLevel = prevInfo.getOutlineLevel();
				startHidden = prevInfo.getHidden();
			}
		}
		if (endLevel > startLevel) {
			return endHidden;
		}
		return startHidden;
	}

	public void collapseColumn(int columnIndex) {
		int colInfoIx = findColInfoIdx(columnIndex, 0);
		if (colInfoIx == -1) {
			return;
		}

		// Find the start of the group.
		int groupStartColInfoIx = findStartOfColumnOutlineGroup(colInfoIx);
		ColumnInfoRecord columnInfo = getColInfo(groupStartColInfoIx);

		// Hide all the columns until the end of the group
		int lastColIx = setGroupHidden(groupStartColInfoIx, columnInfo.getOutlineLevel(), true);

		// Write collapse field
		setColumn(lastColIx + 1, null, null, null, null, Boolean.TRUE);
	}
	/**
	 * Sets all adjacent columns of the same outline level to the specified hidden status.
	 * @param pIdx the col info index of the start of the outline group
	 * @return the column index of the last column in the outline group
	 */
	private int setGroupHidden(int pIdx, int level, boolean hidden) {
		int idx = pIdx;
		ColumnInfoRecord columnInfo = getColInfo(idx);
		while (idx < records.size()) {
			columnInfo.setHidden(hidden);
			if (idx + 1 < records.size()) {
				ColumnInfoRecord nextColumnInfo = getColInfo(idx + 1);
				if (!columnInfo.isAdjacentBefore(nextColumnInfo)) {
					break;
				}
				if (nextColumnInfo.getOutlineLevel() < level) {
					break;
				}
				columnInfo = nextColumnInfo;
			}
			idx++;
		}
		return columnInfo.getLastColumn();
	}


	public void expandColumn(int columnIndex) {
		int idx = findColInfoIdx(columnIndex, 0);
		if (idx == -1) {
			return;
		}

		// If it is already expanded do nothing.
		if (!isColumnGroupCollapsed(idx)) {
			return;
		}

		// Find the start/end of the group.
		int startIdx = findStartOfColumnOutlineGroup(idx);
		int endIdx = findEndOfColumnOutlineGroup(idx);

		// expand:
		// colapsed bit must be unset
		// hidden bit gets unset _if_ surrounding groups are expanded you can determine
		//   this by looking at the hidden bit of the enclosing group.  You will have
		//   to look at the start and the end of the current group to determine which
		//   is the enclosing group
		// hidden bit only is altered for this outline level.  ie.  don't uncollapse contained groups
		ColumnInfoRecord columnInfo = getColInfo(endIdx);
		if (!isColumnGroupHiddenByParent(idx)) {
			int outlineLevel = columnInfo.getOutlineLevel();
			for (int i = startIdx; i <= endIdx; i++) {
				ColumnInfoRecord ci = getColInfo(i);
				if (outlineLevel == ci.getOutlineLevel())
					ci.setHidden(false);
			}
		}

		// Write collapse flag (stored in a single col info record after this outline group)
		setColumn(columnInfo.getLastColumn() + 1, null, null, null, null, Boolean.FALSE);
	}

	private static ColumnInfoRecord copyColInfo(ColumnInfoRecord ci) {
		return ci.copy();
	}


	public void setColumn(int targetColumnIx, Short xfIndex, Integer width,
					Integer level, Boolean hidden, Boolean collapsed) {
		ColumnInfoRecord ci = null;
		int k;
		for (k = 0; k < records.size(); k++) {
			ColumnInfoRecord tci = records.get(k);
			if (tci.containsColumn(targetColumnIx)) {
				ci = tci;
				break;
			}
			if (tci.getFirstColumn() > targetColumnIx) {
				// call column infos after k are for later columns
				break; // exit now so k will be the correct insert pos
			}
		}

		if (ci == null) {
			// okay so there ISN'T a column info record that covers this column so lets create one!
			ColumnInfoRecord nci = new ColumnInfoRecord();

			nci.setFirstColumn(targetColumnIx);
			nci.setLastColumn(targetColumnIx);
			setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
			insertColumn(k, nci);
			attemptMergeColInfoRecords(k);
			return;
		}

		boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
		boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
		boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
		boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
		boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();

		boolean columnChanged = styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
		if (!columnChanged) {
			// do nothing...nothing changed.
			return;
		}

		if (ci.getFirstColumn() == targetColumnIx && ci.getLastColumn() == targetColumnIx) {
			// ColumnInfo ci for a single column, the target column
			setColumnInfoFields(ci, xfIndex, width, level, hidden, collapsed);
			attemptMergeColInfoRecords(k);
			return;
		}

		if (ci.getFirstColumn() == targetColumnIx || ci.getLastColumn() == targetColumnIx) {
			// The target column is at either end of the multi-column ColumnInfo ci
			// we'll just divide the info and create a new one
			if (ci.getFirstColumn() == targetColumnIx) {
				ci.setFirstColumn(targetColumnIx + 1);
			} else {
				ci.setLastColumn(targetColumnIx - 1);
				k++; // adjust insert pos to insert after
			}
			ColumnInfoRecord nci = copyColInfo(ci);

			nci.setFirstColumn(targetColumnIx);
			nci.setLastColumn(targetColumnIx);
			setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );

			insertColumn(k, nci);
			attemptMergeColInfoRecords(k);
		} else {
			//split to 3 records
            ColumnInfoRecord ciMid = copyColInfo(ci);
			ColumnInfoRecord ciEnd = copyColInfo(ci);
			int lastcolumn = ci.getLastColumn();

			ci.setLastColumn(targetColumnIx - 1);

			ciMid.setFirstColumn(targetColumnIx);
			ciMid.setLastColumn(targetColumnIx);
			setColumnInfoFields(ciMid, xfIndex, width, level, hidden, collapsed);
			insertColumn(++k, ciMid);

			ciEnd.setFirstColumn(targetColumnIx+1);
			ciEnd.setLastColumn(lastcolumn);
			insertColumn(++k, ciEnd);
			// no need to attemptMergeColInfoRecords because we
			// know both on each side are different
		}
	}

	/**
	 * Sets all non null fields into the <code>ci</code> parameter.
	 */
	private static void setColumnInfoFields(ColumnInfoRecord ci, Short xfStyle, Integer width,
				Integer level, Boolean hidden, Boolean collapsed) {
		if (xfStyle != null) {
			ci.setXFIndex(xfStyle.shortValue());
		}
		if (width != null) {
			ci.setColumnWidth(width.intValue());
		}
		if (level != null) {
			ci.setOutlineLevel( level.shortValue() );
		}
		if (hidden != null) {
			ci.setHidden( hidden.booleanValue() );
		}
		if (collapsed != null) {
			ci.setCollapsed( collapsed.booleanValue() );
		}
	}

	private int findColInfoIdx(int columnIx, int fromColInfoIdx) {
		if (columnIx < 0) {
			throw new IllegalArgumentException( "column parameter out of range: " + columnIx );
		}
		if (fromColInfoIdx < 0) {
			throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromColInfoIdx );
		}

		for (int k = fromColInfoIdx; k < records.size(); k++) {
			ColumnInfoRecord ci = getColInfo(k);
			if (ci.containsColumn(columnIx)) {
				return k;
			}
			if (ci.getFirstColumn() > columnIx) {
				break;
			}
		}
		return -1;
	}

	/**
	 * Attempts to merge the col info record at the specified index
	 * with either or both of its neighbours
	 */
	private void attemptMergeColInfoRecords(int colInfoIx) {
		int nRecords = records.size();
		if (colInfoIx < 0 || colInfoIx >= nRecords) {
			throw new IllegalArgumentException("colInfoIx " + colInfoIx
					+ " is out of range (0.." + (nRecords-1) + ")");
		}
		ColumnInfoRecord currentCol = getColInfo(colInfoIx);
		int nextIx = colInfoIx+1;
		if (nextIx < nRecords) {
			if (mergeColInfoRecords(currentCol, getColInfo(nextIx))) {
    			records.remove(nextIx);
			}
		}
		if (colInfoIx > 0) {
			if (mergeColInfoRecords(getColInfo(colInfoIx - 1), currentCol)) {
    			records.remove(colInfoIx);
    		}
		}
	}
	/**
	 * merges two column info records (if they are adjacent and have the same formatting, etc)
	 * @return <code>false</code> if the two column records could not be merged
	 */
	private static boolean mergeColInfoRecords(ColumnInfoRecord ciA, ColumnInfoRecord ciB) {
		if (ciA.isAdjacentBefore(ciB) && ciA.formatMatches(ciB)) {
			ciA.setLastColumn(ciB.getLastColumn());
			return true;
		}
		return false;
	}
	/**
	 * Creates an outline group for the specified columns, by setting the level
	 * field for each col info record in the range. {@link ColumnInfoRecord}s
	 * may be created, split or merged as a result of this operation.
	 *
	 * @param fromColumnIx
	 *            group from this column (inclusive)
	 * @param toColumnIx
	 *            group to this column (inclusive)
	 * @param indent
	 *            if <code>true</code> the group will be indented by one
	 *            level, if <code>false</code> indenting will be decreased by
	 *            one level.
	 */
	public void groupColumnRange(int fromColumnIx, int toColumnIx, boolean indent) {

		int colInfoSearchStartIdx = 0; // optimization to speed up the search for col infos
		for (int i = fromColumnIx; i <= toColumnIx; i++) {
			int level = 1;
			int colInfoIdx = findColInfoIdx(i, colInfoSearchStartIdx);
			if (colInfoIdx != -1) {
				level = getColInfo(colInfoIdx).getOutlineLevel();
				if (indent) {
					level++;
				} else {
					level--;
				}
				level = Math.max(0, level);
				level = Math.min(7, level);
				colInfoSearchStartIdx = Math.max(0, colInfoIdx - 1); // -1 just in case this column is collapsed later.
			}
			setColumn(i, null, null, Integer.valueOf(level), null, null);
		}
	}

	/**
	 * Finds the <tt>ColumnInfoRecord</tt> which contains the specified columnIndex
	 * @param columnIndex index of the column (not the index of the ColumnInfoRecord)
	 * @return <code>null</code> if no column info found for the specified column
	 */
	public ColumnInfoRecord findColumnInfo(int columnIndex) {
		int nInfos = records.size();
		for(int i=0; i< nInfos; i++) {
			ColumnInfoRecord ci = getColInfo(i);
			if (ci.containsColumn(columnIndex)) {
				return ci;
			}
		}
		return null;
	}

	public int getMaxOutlineLevel() {
		int result = 0;
		int count=records.size();
		for (int i=0; i<count; i++) {
			ColumnInfoRecord columnInfoRecord = getColInfo(i);
			result = Math.max(columnInfoRecord.getOutlineLevel(), result);
		}
		return result;
	}

	public int getOutlineLevel(int columnIndex) {
	    ColumnInfoRecord ci = findColumnInfo(columnIndex);
	    if (ci != null) {
            return ci.getOutlineLevel();
	    } else {
	        return 0;
	    }
	}

	public int getMinColumnIndex() {
		if(records.isEmpty()) {
			return 0;
		}

		int minIndex = Integer.MAX_VALUE;
		int nInfos = records.size();
		for(int i=0; i< nInfos; i++) {
			ColumnInfoRecord ci = getColInfo(i);
			minIndex = Math.min(minIndex, ci.getFirstColumn());
		}

		return minIndex;
	}

	public int getMaxColumnIndex() {
		if(records.isEmpty()) {
			return 0;
		}

		int maxIndex = 0;
		int nInfos = records.size();
		for(int i=0; i< nInfos; i++) {
			ColumnInfoRecord ci = getColInfo(i);
			maxIndex = Math.max(maxIndex, ci.getLastColumn());
		}

		return maxIndex;
	}

	private static int compareColInfos(ColumnInfoRecord a, ColumnInfoRecord b) {
		return a.getFirstColumn()-b.getFirstColumn();
	}
}
