/*
 * Copyright (C) 2007 Steve Ratcliffe
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 * 
 * Author: Steve Ratcliffe
 * Create date: Dec 14, 2007
 */
package uk.me.parabola.imgfmt.app;

import java.nio.charset.StandardCharsets;
import java.util.Date;

import uk.me.parabola.imgfmt.ReadFailedException;
import uk.me.parabola.imgfmt.Utils;

/**
 * The header that is common to all application files within the .img file.
 * It basically contains two things of interest, the size of the header and
 * its type.  The type is usually of the form 'GARMIN.YYY' where YYY is the
 * file extension of the type eg TRE, LBL, RGN etc.
 *
 * @author Steve Ratcliffe
 */
public abstract class CommonHeader {
	protected static final int COMMON_HEADER_LEN = 21;
	private static final int TYPE_LEN = 10;

	// The common header contains the length and the type which are set at
	// construction time.
	private int headerLength;
	private String type;

	// Set to 0x80 on locked maps.  We are not interested in creating locked
	// maps, but may be useful to recognise them for completeness.
	private byte lockFlag;

	// A date of creation.
	private Date creationDate;

	protected CommonHeader(int headerLength, String type) {
		this.headerLength = headerLength;
		this.type = type;
	}

	/**
	 * Writes out the header that is common to all the file types.  It should
	 * be called by the sync() methods of subclasses when they are ready.
	 * @param writer Used to write the header.
	 */
	public final void writeHeader(ImgFileWriter writer)  {
		writePrepare();

		writer.position(0);

		writer.put2u(headerLength);
		writer.put(Utils.toBytes(type, TYPE_LEN, (byte) 0));

		writer.put1u(1);  // unknown
		writer.put1u(0);  // not locked

		byte[] date = Utils.makeCreationTime(new Date());
		writer.put(date);

		writeFileHeader(writer);
	}

	/**
	 * Read the common header.  It starts at the beginning of the file.
	 * @param reader Used to read the header.
	 */
	public final void readHeader(ImgFileReader reader) throws ReadFailedException {
		reader.position(reader.getGMPOffset());
		headerLength = reader.get2u();
		byte[] bytes = reader.get(TYPE_LEN);
		type = new String(bytes, StandardCharsets.US_ASCII);
		reader.get(); // ignore
		this.lockFlag = reader.get(); // 0x80 if locked

		byte[] date = reader.get(7);
		creationDate = Utils.makeCreationTime(date);

		readFileHeader(reader);
	}

	/**
	 * Read the rest of the header.  Specific to the given file.  It is
	 * guaranteed that the file position will be set to the correct place
	 * before this is called.
	 * @param reader The header is read from here.
	 */
	protected abstract void readFileHeader(ImgFileReader reader) throws ReadFailedException;

	/**
	 * Write the rest of the header.  It is guaranteed that the writer will
	 * be set to the correct position before calling.
	 * @param writer The header is written here.
	 */
	protected abstract void writeFileHeader(ImgFileWriter writer);

	public int getHeaderLength() {
		return headerLength;
	}

	private void writePrepare() {
		// Prepare for write by setting our defaults.
		// lockFlag = 0;
		if (creationDate == null)
			creationDate = new Date();
	}

	/**
	 * @return the lockFlag
	 */
	public byte getLockFlag() {
		return lockFlag;
	}
}
