1 /**
2 *   Copyright: © 2012-2014 Anton Gushcha
3 *   License: Subject to the terms of the MIT license, as written in the included LICENSE file.
4 *   Authors:  NCrashed <ncrashed@gmail.com>,
5 *             LeMarwin <lemarwin42@gmail.com>,
6 *             Nazgull09 <nazgull90@gmail.com>
7 */
8 module devol.type;
9 
10 import std.array;
11 
12 public
13 {
14 	import devol.argument;
15 }
16 
17 alias Argument delegate(Argument val) ConvertorFunc;
18  
19 class ConvAddException : Exception
20 {
21 	this(string s, ConvertorFunc conv, Type type)
22 	{
23 		super(s);
24 		eConv = conv;
25 		eType = type;
26 	}
27 	
28 	ConvertorFunc eConv;
29 	Type eType;
30 }
31 
32 class ConvException : Exception
33 {
34 	this( string s, Type from, Type to)
35 	{
36 		super(s);
37 		eFrom = from;
38 		eTo = to;
39 	}
40 
41 	Type eFrom;
42 	Type eTo;
43 }
44 
45 class Type
46 {
47 	this(string name)
48 	{
49 		sName = name;
50 	}
51 	
52 	@property string name()
53 	{
54 		return sName;
55 	}
56 	
57 	Argument getNewArg()
58 	{
59 		throw new Exception("Pure type isn't allowed to generate args!");
60 	}
61 	
62 	Argument getNewArg(string min, string max, string[] exVal)
63 	{
64 		throw new Exception("Pure type isn't allowed to generate args!");
65 	}
66 	
67 	void registerConvertor( ConvertorFunc func, Type toType )
68 	{
69 		if (toType is null) return;
70 		
71 		if (toType in convs)
72 		{
73 			throw new ConvAddException("Convertor already exists!", convs[toType], toType);
74 		}
75 		
76 		convs[toType] = func;
77 	}
78 	
79 	Argument convert(Argument val)
80 	{
81 		Type type = val.type;
82 		
83 		if(type.name == name ) return val;
84 		
85 		if (this in type.convs)
86 		{
87 			return type.convs[this](val);
88 		}
89 		
90 		auto chain = findConvWay(type);
91 		if (chain.empty)
92 		{
93 			throw new ConvException("Types uncovertable!", type, this);
94 		}
95 		
96 		foreach(conv; chain)
97 		{
98 			val = conv(val);
99 		}
100 		return val;
101 	}
102 	
103 	bool isConvertable(Type from)
104 	{
105 		if (from.name == name ) return true;
106 		
107 		if (this in from.convs)
108 		{
109 			return true;
110 		}
111 		
112 		auto chain = findConvWay(from);		
113 		return !chain.empty;
114 	}
115 	
116 	private ConvertorFunc[] findConvWay(Type from)
117 	{
118 		class Node
119 		{
120 			Node parent;
121 			Type type;
122 			ConvertorFunc func;
123 		}
124 		
125 		Node[] stack = new Node[0];
126 		Type[] blackList = new Type[0];
127 		
128 		Node prevNode = new Node;
129 		prevNode.parent = null;
130 		prevNode.func = null;
131 		bool finded = false;
132 		
133 		finddo: do
134 		{
135 			blackList ~= from;
136 			foreach(type,conv; from.convs)
137 			{
138 				Node node = new Node;
139 				node.parent = prevNode;
140 				node.func = conv;
141 				
142 				bool isInBL(Type t, Type[] bl)
143 				{
144 					foreach( type; bl)
145 						if (t == type)
146 							return true;
147 					return false;
148 				}
149 				
150 				if (!isInBL(type, blackList))
151 					stack ~= node;
152 				
153 				if (type == this)
154 				{
155 					finded = true;
156 					break finddo;
157 				}
158 			}
159 			
160 			if (!stack.empty)
161 			{
162 				prevNode = stack[0];
163 				from = prevNode.type;
164 				stack = stack[1..$];
165 			}
166 			
167 		} while(!stack.empty);
168 		
169 		auto chain = new ConvertorFunc[0];
170 		if (!finded)
171 			return chain;
172 			
173 		auto node = stack[$-1];
174 		while(node.parent !is null)
175 		{
176 			chain = node.func ~ chain;
177 			node = node.parent;
178 		}
179 		return chain;
180 	}
181 	
182 	private ConvertorFunc[Type] convs;
183 	private string sName;
184 }