/*
 * Copyright 2014-2015 See AUTHORS file.
 *
 * Licensed 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 com.kotcrab.vis.runtime.scene;

import com.artemis.BaseSystem;
import com.badlogic.gdx.utils.Array;

/** @author Kotcrab */
public class SceneConfig {
	private Array<ConfigElement> elements = new Array<ConfigElement>();

	public SceneConfig () {
		registerFeatureGroup(SceneFeatureGroup.ESSENTIAL, Priority.VIS_ESSENTIAL);
		registerFeatureGroup(SceneFeatureGroup.INFLATER, Priority.VIS_INFLATER);
		registerFeatureGroup(SceneFeatureGroup.PHYSICS, Priority.VHS_PHYSICS);
		registerFeatureGroup(SceneFeatureGroup.RENDERER, Priority.VIS_RENDERER);
		registerFeatureGroup(SceneFeatureGroup.PHYSICS_DEBUG, Priority.VIS_OTHER);

		registerFeature(SceneFeature.DIRTY_CLEANER_SYSTEM, Priority.VIS_OTHER);

		disable(SceneFeature.GROUP_ID_MANAGER);
		disable(SceneFeature.BOX2D_DEBUG_RENDER_SYSTEM);
	}

	public SceneConfig addSystem (BaseSystem system) {
		return addSystem(new SimpleSystemProvider(system));
	}

	public SceneConfig addSystem (BaseSystem system, int priority) {
		return addSystem(new SimpleSystemProvider(system), priority);
	}

	public SceneConfig addSystem (SystemProvider provider, int priority) {
		elements.add(new ConfigElement(provider, priority));
		return this;
	}

	public SceneConfig addSystem (SystemProvider provider) {
		elements.add(new ConfigElement(provider, Priority.NORMAL));
		return this;
	}

	public SceneConfig disable (SceneFeature feature) {
		for (ConfigElement element : elements) {
			if (element.feature == feature) {
				element.disabled = true;
				return this;
			}
		}

		return this;
	}

	public SceneConfig disable (SceneFeatureGroup featureGroup) {
		for (SceneFeature feature : featureGroup.features) {
			disable(feature);
		}

		return this;
	}

	public SceneConfig enable (SceneFeature feature) {
		for (ConfigElement element : elements) {
			if (element.feature == feature) {
				element.disabled = false;
				return this;
			}
		}

		return this;
	}

	public SceneConfig enable (SceneFeatureGroup featureGroup) {
		for (SceneFeature feature : featureGroup.features) {
			enable(feature);
		}

		return this;
	}

	public SceneConfig replace (SceneFeature feature, SystemProvider newProvider) {
		for (ConfigElement element : elements) {
			if (element.feature == feature) {
				element.provider = newProvider;
				return this;
			}
		}

		return this;
	}

	private void registerFeature (SceneFeature feature, int priority) {
		elements.add(new ConfigElement(feature, feature.defaultProvider, priority));
	}

	private void registerFeatureGroup (SceneFeatureGroup group, int priority) {
		for (SceneFeature feature : group.features) {
			registerFeature(feature, priority);
		}
	}

	void sort () {
		elements.sort();
	}

	Array<ConfigElement> getConfigElements () {
		return elements;
	}

	static class ConfigElement implements Comparable<ConfigElement> {
		SceneFeature feature;
		boolean disabled; //disabled can be only set if feature is set

		SystemProvider provider;
		int priority;

		public ConfigElement (SceneFeature feature, SystemProvider provider, int priority) {
			this.feature = feature;
			this.provider = provider;
			this.priority = priority;
		}

		public ConfigElement (SystemProvider provider, int priority) {
			this.provider = provider;
			this.priority = priority;
		}

		@Override
		public int compareTo (ConfigElement other) {
			return Integer.compare(priority, other.priority);
		}
	}

	public static class Priority {
		public static final int LOWEST = Integer.MIN_VALUE;
		public static final int LOW = -100000;
		public static final int VIS_ESSENTIAL = -10000;
		public static final int VIS_INFLATER = -9000;
		public static final int VHS_PHYSICS = -8000;
		public static final int VIS_RENDERER = -7000;
		public static final int VIS_OTHER = -5000;
		public static final int NORMAL = 0;
		public static final int HIGH = 100000;
		public static final int HIGHEST = Integer.MAX_VALUE;
	}
}

@@ -1290,29 +1290,27 @@
 riority.VIS_
-OTHER
+LOW
 );%0A%0A%09%09disabl
@@ -3916,16 +3916,17 @@
 %09return 
+-
 Integer.
@@ -3964,24 +3964,171 @@
 y);%0A%09%09%7D%0A%09%7D%0A%0A
+%09/**%0A%09 * Defines priorities for entity engine systems. Systems with high priorities will be processed before systems with%0A%09 * low priorities.%0A%09 */%0A
 %09public stat
@@ -4272,26 +4272,55 @@
 int 
-VIS_ESSENTIAL = -1
+NORMAL = 0;%0A%09%09public static final int HIGH = 10
 0000
@@ -4351,29 +4351,37 @@
 int 
-VIS_INFLATER = -9000;
+HIGHEST = Integer.MAX_VALUE;%0A
 %0A%09%09p
@@ -4408,23 +4408,21 @@
 nt V
-HS_PHYSICS
+IS_LOW
  = -
-8
+200
 000;
@@ -4456,21 +4456,23 @@
 VIS_
-RENDERER = -7
+ESSENTIAL = 200
 000;
@@ -4506,18 +4506,21 @@
 VIS_
-OTH
+INFLAT
 ER = 
--5
+19
 000;
@@ -4542,33 +4542,42 @@
 c final int 
-NORMAL = 
+VHS_PHYSICS = 1800
 0;%0A%09%09public 
@@ -4589,34 +4589,41 @@
 c final int 
-HIGH
+VIS_RENDERER
  = 1
-00
+7
 000;%0A%09%09publi
@@ -4645,35 +4645,25 @@
 int 
-HIGHEST = Integer.MAX_VALUE
+VIS_OTHER = 16000
 ;%0A%09%7D

Update priorities values and change order