package org.dbgl.gui.controls;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.IntStream;

import org.dbgl.gui.controls.MetaControl.TriConsumer;
import org.dbgl.gui.interfaces.DaControlConvertor;
import org.dbgl.model.aggregate.Profile;
import org.dbgl.model.aggregate.Template;
import org.dbgl.model.conf.Autoexec;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;


public class Chain {

	final private Control[] controls_;
	final private Label[] labels_;
	final private Text[] texts_;
	final private Combo[] combos_;
	final private Button[] buttons_;
	final private org.eclipse.swt.widgets.List[] lists_;
	final private Spinner[] spinners_;
	final private Scale[] scales_;

	public Chain(Builder builder) {
		controls_ = builder.controls_.toArray(new Control[builder.controls_.size()]);
		labels_ = builder.labels_.toArray(new Label[builder.labels_.size()]);
		texts_ = builder.texts_.toArray(new Text[builder.texts_.size()]);
		combos_ = builder.combos_.toArray(new Combo[builder.combos_.size()]);
		buttons_ = builder.buttons_.toArray(new Button[builder.buttons_.size()]);
		lists_ = builder.lists_.toArray(new org.eclipse.swt.widgets.List[builder.lists_.size()]);
		spinners_ = builder.spinners_.toArray(new Spinner[builder.spinners_.size()]);
		scales_ = builder.scales_.toArray(new Scale[builder.scales_.size()]);

		if (builder.da_ != null)
			builder.da_.add(builder.daControlBuilder_.label(labels_[0]).controls(controls_).build());
		else if (builder.meta_ != null)
			builder.meta_.add(builder.metaControlBuilder_.label(labels_[0]).controls(controls_).build());
	}

	public Label[] getLabels() {
		return labels_;
	}

	public Label getLabel() {
		return labels_[0];
	}

	public Text[] getTexts() {
		return texts_;
	}

	public Text getText() {
		return texts_[0];
	}

	public Combo[] getCombos() {
		return combos_;
	}

	public Combo getCombo() {
		return combos_[0];
	}

	public Button[] getButtons() {
		return buttons_;
	}

	public Button getButton() {
		return buttons_[0];
	}

	public org.eclipse.swt.widgets.List[] getLists() {
		return lists_;
	}

	public org.eclipse.swt.widgets.List getList() {
		return lists_[0];
	}

	public Spinner[] getSpiners() {
		return spinners_;
	}

	public Spinner getSpinner() {
		return spinners_[0];
	}

	public Scale[] getScales() {
		return scales_;
	}

	public Scale getScale() {
		return scales_[0];
	}

	public static Builder on(Composite composite) {
		return new Builder(composite);
	}

	public static final class Builder {
		final private Composite composite_;
		private List<Control> controls_;
		private List<Label> labels_;
		private List<Text> texts_;
		private List<Combo> combos_;
		private List<Button> buttons_;
		private List<org.eclipse.swt.widgets.List> lists_;
		private List<Spinner> spinners_;
		private List<Scale> scales_;

		private List<DaControl> da_;
		private DaControl.Builder daControlBuilder_ = DaControl.builder();
		private List<MetaControl> meta_;
		private MetaControl.Builder metaControlBuilder_ = MetaControl.builder();

		public Builder(Composite composite) {
			composite_ = composite;
			controls_ = new ArrayList<>();
			labels_ = new ArrayList<>();
			texts_ = new ArrayList<>();
			combos_ = new ArrayList<>();
			buttons_ = new ArrayList<>();
			lists_ = new ArrayList<>();
			spinners_ = new ArrayList<>();
			scales_ = new ArrayList<>();
		}

		public Builder lbl(Function<Label_.Builder, Label_.Builder> lb) {
			labels_.add(lb.apply(Label_.on(composite_)).ctrl());
			return this;
		}

		public Builder txt(Function<Text_.Builder, Text_.Builder> tb) {
			texts_.add(tb.apply(Text_.on(composite_)).ctrl());
			controls_.add(texts_.get(texts_.size() - 1));
			return this;
		}

		public Builder cmb(Function<Combo_.Builder, Combo_.Builder> cb) {
			combos_.add(cb.apply(Combo_.on(composite_)).ctrl());
			controls_.add(combos_.get(combos_.size() - 1));
			return this;
		}

		public Builder but(Function<Button_.Builder, Button_.Builder> bb) {
			TextControl_ textControl = !texts_.isEmpty() ? new TextControl_(texts_.get(texts_.size() - 1)): !combos_.isEmpty() ? new TextControl_(combos_.get(combos_.size() - 1)): null;
			Button button = bb.apply(Button_.on(composite_)).ctrl(textControl);
			buttons_.add(button);
			if (IntStream.of(SWT.RADIO, SWT.TOGGLE, SWT.CHECK).anyMatch(x -> (button.getStyle() & x) == x))
				controls_.add(button);
			return this;
		}

		public Builder lst(Function<List_.Builder, List_.Builder> lb) {
			lists_.add(lb.apply(List_.on(composite_)).ctrl());
			controls_.add(lists_.get(lists_.size() - 1));
			return this;
		}

		public Builder spn(Function<Spinner_.Builder, Spinner_.Builder> sb) {
			spinners_.add(sb.apply(Spinner_.on(composite_)).ctrl());
			controls_.add(spinners_.get(spinners_.size() - 1));
			return this;
		}

		public Builder scl(Function<Scale_.Builder, Scale_.Builder> sb) {
			scales_.add(sb.apply(Scale_.on(composite_)).ctrl());
			controls_.add(scales_.get(scales_.size() - 1));
			return this;
		}

		public Builder da(List<DaControl> daControls) {
			da_ = daControls;
			return this;
		}

		public Builder section(String section) {
			daControlBuilder_.section(section);
			return this;
		}

		public Builder section(String sectionOld, String sectionNew) {
			daControlBuilder_.section(sectionOld, sectionNew);
			return this;
		}

		public Builder item(String item) {
			daControlBuilder_.item(item);
			return this;
		}

		public Builder item(String itemOld, String itemNew) {
			daControlBuilder_.item(itemOld, itemNew);
			return this;
		}

		public Builder onOff() {
			daControlBuilder_.onOff();
			return this;
		}

		public Builder convert(DaControlConvertor convertor) {
			daControlBuilder_.convert(convertor);
			return this;
		}

		public Builder meta(List<MetaControl> metaControls) {
			meta_ = metaControls;
			return this;
		}

		public Builder template(Function<Template, String> getMethod, BiConsumer<Template, String> updateMethod) {
			metaControlBuilder_.template(getMethod, updateMethod);
			return this;
		}

		public Builder profile(Function<Profile, String> getMethod, BiConsumer<Profile, String> updateMethod) {
			metaControlBuilder_.profile(getMethod, updateMethod);
			return this;
		}

		public Builder profile(int i, BiFunction<Profile, Integer, String> getMethod, TriConsumer<Profile, Integer, String> updateMethod) {
			metaControlBuilder_.profile(i, getMethod, updateMethod);
			return this;
		}

		public Builder autoexec(Function<Autoexec, String> getMethod, BiConsumer<Autoexec, String> updateMethod) {
			metaControlBuilder_.autoexec(getMethod, updateMethod);
			return this;
		}

		public Builder autoexec(int i, BiFunction<Autoexec, Integer, String> getMethod, TriConsumer<Autoexec, Integer, String> updateMethod) {
			metaControlBuilder_.autoexec(i, getMethod, updateMethod);
			return this;
		}

		public Chain build() {
			return new Chain(this);
		}

		public Label label() {
			return build().getLabel();
		}

		public Text text() {
			return build().getText();
		}

		public Combo combo() {
			return build().getCombo();
		}

		public Button button() {
			return build().getButton();
		}

		public org.eclipse.swt.widgets.List list() {
			return build().getList();
		}

		public Spinner spinner() {
			return build().getSpinner();
		}

		public Scale scale() {
			return build().getScale();
		}
	}
}
