/*
 * Copyright (c) 2014-2021 by Wen Yu
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the Eclipse
 * Public License, v. 2.0 are satisfied: GNU General Public License, version 2
 * or any later version.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
 *
 * Change History - most recent changes go on top of previous changes
 *
 * IFD.java
 *
 * Who   Date       Description
 * ====  =========  =======================================================================
 * WY    15Dec2014  Added removeChild() method
 * WY    24Nov2014  Added getChild() method
 * WY    02Apr2014  Added setNextIFDOffset() to work with the case of non-contiguous IFDs
 * WY    30Mar2014  Added children map, changed write() method to write child nodes as well.
 */

package pixy.image.tiff;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pixy.io.RandomAccessOutputStream;
import pixy.string.StringUtils;

/**
 * Image File Directory
 *
 * @author Wen Yu, yuwen_66@yahoo.com
 * @version 1.0 01/04/2013
 */
public final class IFD {
		
	/**
	 * Create a children map for sub IFDs. A sub IFD is associated with a tag of the current IFD
	 * which serves as pointer to the sub IFD.
	 */	 
	private Map<Tag, IFD> children = new HashMap<Tag, IFD>();
	
	/** Create a fields map to hold all of the fields for this IFD */
	private Map<Short, TiffField<?>> tiffFields = new HashMap<Short, TiffField<?>>();

	private int endOffset;
	
	private int startOffset;
	
	public IFD() {}
	
	// Copy constructor
	public IFD(IFD other) {
		// Defensive copy
		this.children = Collections.unmodifiableMap(other.children);
		this.tiffFields = Collections.unmodifiableMap(other.tiffFields);
		this.startOffset = other.startOffset;
		this.endOffset = other.endOffset;
	}
	
	public void addChild(Tag tag, IFD child) {
		children.put(tag, child);
	}
	
	public void addField(TiffField<?> tiffField) {
		tiffFields.put(tiffField.getTag(), tiffField);
	}
	
	public void addFields(Collection<TiffField<?>> tiffFields) {
		for(TiffField<?> field : tiffFields) {
			addField(field);
		}
	}
	
	public IFD getChild(Tag tag) {
		return children.get(tag);
	}
	
	public Map<Tag, IFD> getChildren() {
		return Collections.unmodifiableMap(children);
	}
	
	public int getEndOffset() {
		return endOffset;
	}
	
	public TiffField<?> getField(Tag tag) {
		return tiffFields.get(tag.getValue());
	}
	
	/**
	 * Return a String representation of the field 
	 * @param tag Tag for the field
	 * @return a String representation of the field
	 */
	public String getFieldAsString(Tag tag) {
		TiffField<?> field = tiffFields.get(tag.getValue());
		if(field != null) {
			FieldType ftype = field.getType();
			String suffix = null;
			if(ftype == FieldType.SHORT || ftype == FieldType.SSHORT)
				suffix = tag.getFieldAsString(field.getDataAsLong());
			else
				suffix = tag.getFieldAsString(field.getData());			
			
			return field.getDataAsString() + (StringUtils.isNullOrEmpty(suffix)?"":" => " + suffix);
		}
		return "";
	}
	
	/** Get all the fields for this IFD from the internal map. */
	public Collection<TiffField<?>> getFields() {
		return Collections.unmodifiableCollection(tiffFields.values());
	}
	
	public int getSize() {
		return tiffFields.size();
	}
	
	public int getStartOffset() {
		return startOffset;
	}
	
	/** Remove all the entries from the IDF fields map */
	public void removeAllFields() {
		tiffFields.clear();
	}
	
	public IFD removeChild(Tag tag) {
		return children.remove(tag);
	}
	
	/** Remove a specific field associated with the given tag */
	public TiffField<?> removeField(Tag tag) {
		return tiffFields.remove(tag.getValue());
	}
	
	/**
	 * Set the next IFD offset pointer
	 * <p>
	 * Note: This should <em>ONLY</em> be called
	 * after the current IFD has been written to the RandomAccessOutputStream
	 *  
	 * @param os RandomAccessOutputStream
	 * @param nextOffset next IFD offset value
	 * @throws IOException
	 */
	public void setNextIFDOffset(RandomAccessOutputStream os, int nextOffset) throws IOException {
		os.seek(endOffset - 4);
		os.writeInt(nextOffset);
	}
	
	/** Write this IFD and all the children, if any, to the output stream
	 * 
	 * @param os RandomAccessOutputStream
	 * @param offset stream offset to write this IFD
	 * 
	 * @throws IOException
	 */
	public int write(RandomAccessOutputStream os, int offset) throws IOException {
		startOffset = offset;
		// Write this IFD and its children, if any, to the RandomAccessOutputStream
		List<TiffField<?>> list = new ArrayList<TiffField<?>>(tiffFields.values());
		// Make sure tiffFields are in incremental order.
		Collections.sort(list);
		os.seek(offset);
		os.writeShort(list.size());
		offset += 2;
		endOffset = offset + list.size() * 12 + 4;			
		// The first available offset to write tiffFields. 
		int toOffset = endOffset;
		os.seek(offset); // Set first field offset.
				
		for (TiffField<?> tiffField : list)
		{
			toOffset = tiffField.write(os, toOffset);
			offset += 12; // Move to next field. Each field is of fixed length 12.
			os.seek(offset); // Reset position to next directory field.
		}
		
		/* Set the stream position at the end of the IFD to update
		 * next IFD offset
		 */
		os.seek(offset);
		os.writeInt(0);	// Set next IFD offset to default 0 
		
		// Write sub IFDs if any (we assume bare-bone sub IFDs pointed by long field type with no image data associated)
		if(children.size() > 0) {
			for (Map.Entry<Tag, IFD> entry : children.entrySet()) {
			    Tag key = entry.getKey();
			    IFD value = entry.getValue();
			    // Update parent field if present, otherwise skip
			    TiffField<?> tiffField = this.getField(key);
			    if(tiffField != null) {
			    	int dataPos = tiffField.getDataOffset();
					os.seek(dataPos);
					os.writeInt(toOffset);
					os.seek(toOffset);
					toOffset = value.write(os, toOffset);
			    }
		    }
		}
			
		return toOffset;
	}
}
