1 module auxil.location;
2 
3 import auxil.model : Orientation; // FIXME avoid import from this module
4 import auxil.treepath;
5 
6 alias SizeType = int;
7 
8 enum Order { Sinking, Bubbling, }
9 
10 struct Axis
11 {
12 	SizeType position, destination, change, size;
13 }
14 
15 @safe
16 struct Location
17 {
18 @nogc:
19 	enum State { seeking, first, rest, finishing, }
20 	State _state;
21 	TreePath current_path, path;
22 	Axis x, y;
23 
24 	@property
25 	{
26 		State state() @safe @nogc nothrow { return _state; }
27 	}
28 
29 	package void resetState() @safe @nogc nothrow
30 	{
31 		_state = (path.value.length) ? State.seeking : State.rest;
32 		y.change = 0;
33 		x.change = 0;
34 	}
35 
36 	/// returns true if the processing should be interrupted
37 	package bool checkState() @safe @nogc
38 	{
39 		final switch(_state)
40 		{
41 			case State.seeking:
42 				if (current_path.value == path.value)
43 					_state = State.first;
44 			break;
45 			case State.first:
46 				_state = State.rest;
47 			break;
48 			case State.rest:
49 				// do nothing
50 			break;
51 			case State.finishing:
52 			{
53 				return true;
54 			}
55 		}
56 		return false;
57 	}
58 
59 	void indent()
60 	{
61 		current_path.put(0);
62 	}
63 
64 	void unindent()
65 	{
66 		current_path.popBack;
67 	}
68 
69 	auto startValue(Order order)(size_t len)
70 	{
71 		import std.algorithm : among;
72 
73 		size_t start_value;
74 		static if (order == Order.Bubbling)
75 		{
76 			start_value = len;
77 			start_value--;
78 		}
79 		if (_state.among(State.seeking, State.first))
80 		{
81 			auto idx = current_path.value.length;
82 			if (idx && path.value.length >= idx)
83 			{
84 				start_value = path.value[idx-1];
85 				// position should change only if we've got the initial path
86 				// and don't get the end
87 				if (_state == State.seeking) y.change = 0;
88 			}
89 		}
90 		return start_value;
91 	}
92 
93 	void setPath(int v)
94 	{
95 		current_path.back = v;
96 	}
97 
98 	bool stateFirstOrRest() @safe @nogc pure nothrow
99 	{
100 		import std.algorithm : among;
101 		return !!_state.among(State.first, State.rest);
102 	}
103 }