/*-
 *  Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
 * 
 *  This file is part of CityDoctor2.
 *
 *  CityDoctor2 is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  CityDoctor2 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with CityDoctor2.  If not, see <https://www.gnu.org/licenses/>.
 */
package de.hft.stuttgart.citydoctor2.parser;

import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.citygml4j.factory.GMLGeometryFactory;
import org.citygml4j.model.citygml.core.AbstractCityObject;

import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;

/**
 * Handler when the CityGML files is split up into seperate features.
 * 
 * @author Matthias Betz
 *
 */
public class FeatureStream {

	private static final Logger logger = LogManager.getLogger(FeatureStream.class);

	private ArrayBlockingQueue<CityObject> queue;
	private String fileName;
	private CityDoctorModel model;
	private boolean closed;

	private Thread readThread;

	private File file;

	static final CityObject POISON = new CityObject() {

		private static final long serialVersionUID = -3476076957438256265L;

		@Override
		public FeatureType getFeatureType() {
			return FeatureType.BUILDING;
		}

		@Override
		public void reCreateGeometries(GMLGeometryFactory factory, ParserConfiguration config) {
			throw new UnsupportedOperationException();
		}

		@Override
		public AbstractCityObject getGmlObject() {
			throw new UnsupportedOperationException();
		}

		@Override
		public void unsetGmlGeometries() {
			throw new UnsupportedOperationException();
		}
	};

	FeatureStream(ArrayBlockingQueue<CityObject> queue, String fileName, File file) {
		this.queue = queue;
		this.fileName = fileName;
		this.file = file;
		closed = false;
	}

	public void setThread(Thread readThread) {
		this.readThread = readThread;
	}

	public String getFileName() {
		return fileName;
	}

	/**
	 * Returns the next element that is parsed or null if no more elements are
	 * available
	 * 
	 * @return the next element or null
	 * @throws InterruptedException if the parsing thread is interrupted
	 */
	public CityObject next() throws InterruptedException {
		CityObject co = queue.take();
		if (co == POISON) {
			if (readThread != null) {
				readThread.join();
			}
			return null;
		}
		return co;
	}

	public void setCityDoctorModel(CityDoctorModel model) {
		this.model = model;
	}

	public CityDoctorModel getCityDoctorModel() {
		return model;
	}

	public void close() {
		if (readThread != null) {
			readThread.interrupt();
		}
		closed = true;
		if (!queue.isEmpty()) {
			queue.poll();
			boolean validOffer = queue.offer(POISON);
			logger.trace("Stream closed while queue not empty, removing element and adding poison element");
			if (!validOffer) {
				logger.trace("Could not add poison element to queue");
			}
		}
	}

	public boolean isClosed() {
		return closed;
	}

	public File getFile() {
		return file;
	}

}
