<commit_before>package org.mwc.debrief.pepys.model.bean;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import org.mwc.debrief.pepys.model.PepsysException;
import org.mwc.debrief.pepys.model.db.Condition;
import org.mwc.debrief.pepys.model.db.DatabaseConnection;
import org.mwc.debrief.pepys.model.db.SqliteDatabaseConnection;
import org.mwc.debrief.pepys.model.db.annotation.FieldName;
import org.mwc.debrief.pepys.model.db.annotation.Id;
import org.mwc.debrief.pepys.model.db.annotation.Location;
import org.mwc.debrief.pepys.model.db.annotation.ManyToOne;
import org.mwc.debrief.pepys.model.db.annotation.TableName;
import org.mwc.debrief.pepys.model.db.annotation.Time;
import org.mwc.debrief.pepys.model.db.annotation.Transient;
import org.mwc.debrief.pepys.model.db.config.ConfigurationReader;
import org.mwc.debrief.pepys.model.db.config.DatabaseConfiguration;
import org.mwc.debrief.pepys.model.db.config.LoaderOption;
import org.mwc.debrief.pepys.model.db.config.LoaderOption.LoaderType;
import org.mwc.debrief.pepys.model.tree.TreeStructurable;

import Debrief.Wrappers.FixWrapper;
import Debrief.Wrappers.TrackWrapper;
import Debrief.Wrappers.Track.LightweightTrackWrapper;
import MWC.GUI.BaseLayer;
import MWC.GUI.Editable;
import MWC.GUI.Layer;
import MWC.GUI.Layers;
import MWC.GenericData.HiResDate;
import MWC.GenericData.WorldLocation;
import MWC.TacticalData.Fix;
import junit.framework.TestCase;

@TableName(name = "States")
public class State implements AbstractBean, TreeStructurable {

	public static class StatesTest extends TestCase {

		public void testStatesQuery() {
			if (System.getProperty("os.name").toLowerCase().indexOf("mac") == -1) {
				try {
					final DatabaseConfiguration _config = new DatabaseConfiguration();
					ConfigurationReader.loadDatabaseConfiguration(_config,
							new LoaderOption[] { new LoaderOption(LoaderType.DEFAULT_FILE,
									DatabaseConnection.DEFAULT_SQLITE_TEST_DATABASE_FILE) });
					final SqliteDatabaseConnection sqlite = new SqliteDatabaseConnection();
					sqlite.initializeInstance(_config);
					final List<State> list = sqlite.listAll(State.class, (Collection<Condition>) null);

					assertTrue("States - database entries", list.size() == 12239);

					final List<State> list2 = sqlite.listAll(State.class, Arrays.asList(
							new Condition[] { new Condition("source_id = \"638471a99e264761830b3f6575816e67\"") }));

					assertTrue("States - database entries", list2.size() == 5);

					final List<State> list3 = sqlite.listAll(State.class, Arrays.asList(
							new Condition[] { new Condition("source_id = \"db8692a392924d27bfacdbddc4eb9a29\"") }));

					assertTrue("States - database entries", list3.size() == 11400);
				} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
						| IllegalArgumentException | InvocationTargetException | PropertyVetoException | SQLException
						| ClassNotFoundException | IOException | PepsysException e) {
					e.printStackTrace();
					fail("Couldn't connect to database or query error");
				}
			}
		}
	}

	@Id
	private String state_id;

	@Time
	private Timestamp time;

	@ManyToOne
	@FieldName(name = "sensor_id")
	private Sensor sensor;
	private double heading;
	private double course;

	private double speed;
	@ManyToOne
	@FieldName(name = "source_id")
	private Datafile datafile;
	private String privacy_id;
	private Timestamp created_date;

	@Location
	private WorldLocation location;

	@Transient
	private int count;

	public State() {

	}

	@Override
	public void doImport(final Layers _layers, final boolean splitByDatafile) {
		final LightweightTrackWrapper track = getParent(_layers, getDatafile().getReference(),
				getPlatform().getTrackName(), splitByDatafile);

		// create the wrapper for this annotation
		final FixWrapper fixWrapper = new FixWrapper(new Fix(new HiResDate(time.getTime()), location, course, speed));
		fixWrapper.setName(time.toString());
		track.add(fixWrapper);
	}

	@Override
	public int getCount() {
		return count;
	}

	public double getCourse() {
		return course;
	}

	public Timestamp getCreated_date() {
		return created_date;
	}

	@Override
	public Datafile getDatafile() {
		return datafile;
	}

	public double getHeading() {
		return heading;
	}

	public WorldLocation getLocation() {
		return location;
	}

	private LightweightTrackWrapper getParent(final Layers layers, final String datafile, final String trackName,
			final boolean splitByDatafile) {
		// first the parent folder
		if (splitByDatafile) {
			Layer parent = layers.findLayer(datafile, false);
			if (parent == null) {
				parent = new BaseLayer();
				parent.setName(datafile);
				layers.addThisLayer(parent);
			}

			// now the track
			LightweightTrackWrapper track = null;
			final Enumeration<Editable> iter = parent.elements();
			while (iter.hasMoreElements() && track == null) {
				final Editable item = iter.nextElement();
				if (item instanceof LightweightTrackWrapper && item.getName().equals(trackName)) {
					track = (LightweightTrackWrapper) item;
				}
			}

			// did we find it?
			if (track == null) {
				// create a new track. Since we're inside a parent folder,
				// just use lightweight track
				track = new LightweightTrackWrapper();
				track.setName(trackName);
				// and store it
				parent.add(track);
			}
			return track;
		} else {
			// If we don't want to split by datafile, then we will add the track directly.
			// Let's find it then
			TrackWrapper track = null;

			final Enumeration<Editable> iter = layers.elements();
			while (iter.hasMoreElements() && track == null) {
				final Editable item = iter.nextElement();
				if (item instanceof TrackWrapper && item.getName().equals(trackName)) {
					track = (TrackWrapper) item;
				}
			}

			// did we find it?
			if (track == null) {
				// create a new track
				track = new TrackWrapper();
				track.setName(trackName);
				// and store it
				layers.addThisLayer(track);
			}

			return track;
		}
	}

	@Override
	public Platform getPlatform() {
		if (sensor != null) {
			return sensor.getPlatform();
		}
		return null;
	}

	public String getPrivacy_id() {
		return privacy_id;
	}

	public Sensor getSensor() {
		return sensor;
	}

	@Override<commit_msg>Minor refactoring, to reduce duplication<commit_after>package org.mwc.debrief.pepys.model.bean;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import org.mwc.debrief.pepys.model.PepsysException;
import org.mwc.debrief.pepys.model.db.Condition;
import org.mwc.debrief.pepys.model.db.DatabaseConnection;
import org.mwc.debrief.pepys.model.db.SqliteDatabaseConnection;
import org.mwc.debrief.pepys.model.db.annotation.FieldName;
import org.mwc.debrief.pepys.model.db.annotation.Id;
import org.mwc.debrief.pepys.model.db.annotation.Location;
import org.mwc.debrief.pepys.model.db.annotation.ManyToOne;
import org.mwc.debrief.pepys.model.db.annotation.TableName;
import org.mwc.debrief.pepys.model.db.annotation.Time;
import org.mwc.debrief.pepys.model.db.annotation.Transient;
import org.mwc.debrief.pepys.model.db.config.ConfigurationReader;
import org.mwc.debrief.pepys.model.db.config.DatabaseConfiguration;
import org.mwc.debrief.pepys.model.db.config.LoaderOption;
import org.mwc.debrief.pepys.model.db.config.LoaderOption.LoaderType;
import org.mwc.debrief.pepys.model.tree.TreeStructurable;

import Debrief.Wrappers.FixWrapper;
import Debrief.Wrappers.TrackWrapper;
import Debrief.Wrappers.Track.LightweightTrackWrapper;
import MWC.GUI.BaseLayer;
import MWC.GUI.Editable;
import MWC.GUI.Layer;
import MWC.GUI.Layers;
import MWC.GenericData.HiResDate;
import MWC.GenericData.WorldLocation;
import MWC.TacticalData.Fix;
import junit.framework.TestCase;

@TableName(name = "States")
public class State implements AbstractBean, TreeStructurable {

	public static class StatesTest extends TestCase {

		public void testStatesQuery() {
			if (System.getProperty("os.name").toLowerCase().indexOf("mac") == -1) {
				try {
					final DatabaseConfiguration _config = new DatabaseConfiguration();
					ConfigurationReader.loadDatabaseConfiguration(_config,
							new LoaderOption[] { new LoaderOption(LoaderType.DEFAULT_FILE,
									DatabaseConnection.DEFAULT_SQLITE_TEST_DATABASE_FILE) });
					final SqliteDatabaseConnection sqlite = new SqliteDatabaseConnection();
					sqlite.initializeInstance(_config);
					final List<State> list = sqlite.listAll(State.class, (Collection<Condition>) null);

					assertTrue("States - database entries", list.size() == 12239);

					final List<State> list2 = sqlite.listAll(State.class, Arrays.asList(
							new Condition[] { new Condition("source_id = \"638471a99e264761830b3f6575816e67\"") }));

					assertTrue("States - database entries", list2.size() == 5);

					final List<State> list3 = sqlite.listAll(State.class, Arrays.asList(
							new Condition[] { new Condition("source_id = \"db8692a392924d27bfacdbddc4eb9a29\"") }));

					assertTrue("States - database entries", list3.size() == 11400);
				} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
						| IllegalArgumentException | InvocationTargetException | PropertyVetoException | SQLException
						| ClassNotFoundException | IOException | PepsysException e) {
					e.printStackTrace();
					fail("Couldn't connect to database or query error");
				}
			}
		}
	}

	@Id
	private String state_id;

	@Time
	private Timestamp time;

	@ManyToOne
	@FieldName(name = "sensor_id")
	private Sensor sensor;
	private double heading;
	private double course;

	private double speed;
	@ManyToOne
	@FieldName(name = "source_id")
	private Datafile datafile;
	private String privacy_id;
	private Timestamp created_date;

	@Location
	private WorldLocation location;

	@Transient
	private int count;

	public State() {

	}

	@Override
	public void doImport(final Layers _layers, final boolean splitByDatafile) {
		final LightweightTrackWrapper track = getParent(_layers, getDatafile().getReference(),
				getPlatform().getTrackName(), splitByDatafile);

		// create the wrapper for this annotation
		final FixWrapper fixWrapper = new FixWrapper(new Fix(new HiResDate(time.getTime()), location, course, speed));
		fixWrapper.setName(time.toString());
		track.add(fixWrapper);
	}

	@Override
	public int getCount() {
		return count;
	}

	public double getCourse() {
		return course;
	}

	public Timestamp getCreated_date() {
		return created_date;
	}

	@Override
	public Datafile getDatafile() {
		return datafile;
	}

	public double getHeading() {
		return heading;
	}

	public WorldLocation getLocation() {
		return location;
	}
	
	private static Layer findLayer(final Layers layers, final String name) {
		Layer parent = layers.findLayer(name, false);
		if (parent == null) {
			parent = new BaseLayer();
			parent.setName(name);
			layers.addThisLayer(parent);
		}
		return parent;
	}
	
	private static LightweightTrackWrapper findTrack(final Enumeration<Editable> iter, final String trackName) {
		LightweightTrackWrapper track = null;
		while (iter.hasMoreElements() && track == null) {
			final Editable item = iter.nextElement();
			if (item instanceof LightweightTrackWrapper && item.getName().equals(trackName)) {
				track = (LightweightTrackWrapper) item;
			}
		}
		return track;
	}

	private LightweightTrackWrapper getParent(final Layers layers, final String datafile, final String trackName,
			final boolean splitByDatafile) {
		if (splitByDatafile) {
			final Layer parent = findLayer(layers, datafile);

			// now the track
			LightweightTrackWrapper track = findTrack(parent.elements(), trackName);

			// did we find it?
			if (track == null) {
				// create a new track. Since we're inside a parent folder,
				// just use lightweight track
				track = new LightweightTrackWrapper();
				track.setName(trackName);
				// and store it
				parent.add(track);
			}
			return track;
		} else {
			// If we don't want to split by datafile, then we will add the track directly.
			// Let's find it then
			LightweightTrackWrapper track = findTrack(layers.elements(), trackName);

			// did we find it?
			if (track == null) {
				// create a new track
				track = new TrackWrapper();
				track.setName(trackName);
				// and store it
				layers.addThisLayer(track);
			}

			return track;
		}
	}

	@Override
	public Platform getPlatform() {
		if (sensor != null) {
			return sensor.getPlatform();
		}
		return null;
	}

	public String getPrivacy_id() {
		return privacy_id;
	}

	public Sensor getSensor() {
		return sensor;
	}

	@Override
{'fraction_non_alphanumeric': 0.10816607936264747, 'fraction_numerical': 0.00903937490424391, 'mean_word_length': 4.346027846027846, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5047009', 'n_tokens_mistral': 4581, 'n_tokens_neox': 3996, 'n_words': 931}