1 module unde.file_manager.find_path;
2 
3 import unde.global_state;
4 import unde.lib;
5 import unde.lsblk;
6 import unde.path_mnt;
7 import unde.slash;
8 
9 import berkeleydb.all;
10 
11 import std.stdio;
12 import std..string;
13 
14 import std.file;
15 
16 version (Windows)
17 {
18 import unde.scan;
19 }
20 
21 enum unDE_Path_Finder_Flags {
22     Go_Up,
23     Go_Down,
24     Out,
25     Try_Other_Directory
26 }
27 
28 private unDE_Path_Finder_Flags
29 what_to_do_with_path_by_rectangle(GlobalState gs,
30         in ref DRect surf_rect, in ref RectSize rectsize,
31         in PathMnt path, DRect apply_rect, in SortType sort,
32         in int level = 0)
33 {
34     if (level == 0)
35     {
36         if (rectsize.rect(sort).In(surf_rect))
37         {
38             if (path > gs.main_path)
39             {
40                 if (gs.path != SL)
41                 {
42                     return unDE_Path_Finder_Flags.Go_Up;
43                 }
44                 else
45                 {
46                     return unDE_Path_Finder_Flags.Try_Other_Directory;
47                 }
48             }
49         }
50     }
51 
52     /*writefln("!%s", path);
53     writefln("R %s, %s, %s, %s", rectsize.rect(sort).x,
54             rectsize.rect(sort).x+rectsize.rect(sort).w,
55             rectsize.rect(sort).y,
56             rectsize.rect(sort).y+rectsize.rect(sort).h);
57     writefln("S %s, %s, %s, %s", surf_rect.x, surf_rect.x+surf_rect.w,
58             surf_rect.y, surf_rect.y+surf_rect.h);*/
59 
60     if (surf_rect.In(rectsize.rect(sort)))
61     {
62         gs.path = path;
63         gs.apply_rect = apply_rect;
64         gs.sort = sort;
65         //writefln("path=%s, apply_rect=%s, sort=%s",
66         //        gs.path, gs.apply_rect, gs.sort);
67     }
68 
69     //writefln("rectsize=%s, surf_rect=%s", rectsize.rect(sort), surf_rect);
70     if (rectsize.rect(sort).In(surf_rect))
71         return unDE_Path_Finder_Flags.Out;
72 
73     if (rectsize.rect(sort).NotIntersect(surf_rect))
74         return unDE_Path_Finder_Flags.Try_Other_Directory;
75 
76     return unDE_Path_Finder_Flags.Go_Down;
77 }
78 
79 version(Windows)
80 {
81 public DRect
82 get_drect_of_drives(GlobalState gs, string drive)
83 {
84 	DRect full_rect = DRect(0, 0, 1024*1024, 1024*1024);
85 	RectSize rectsize = RectSize(full_rect, full_rect, full_rect);
86 
87 	int ret = 0;
88 
89 	string[] paths;
90 
91 	foreach(char c; 'A'..'Z'+1)
92 	{
93 		string disk = c ~ ":";
94 		if ( disk in gs.lsblk )
95 		{
96 			paths ~= disk;
97 		}
98 	}
99 
100 	int levels = 0;
101 	long l = paths.length;
102 	/*if (l > 0)
103 	  {
104 	  l--;
105 	  }*/
106 	for (long i=12; i < l; i=i*2+12)
107 	{
108 		l -= i;
109 		levels++;
110 	}
111 	if (l > 0) levels++;
112 
113 	immutable long entries_on_last_level = l;
114 
115 	//RectSize[string] rect_sizes;
116 
117 	//writefln("levels = %s", levels);
118 	long[] coords = new long[levels+1];
119 	long i = 0;
120 	size_t lev = 1;
121 	bool first = true;
122 	foreach (string name; paths)
123 	{
124 		DRect rect;
125 		calculate_rect(full_rect, rect, coords, lev);
126 
127 		if (name == drive) return rect;
128 
129 		calculate_coords(coords, lev, i, levels, entries_on_last_level);
130 		first = false;
131 	}
132 
133 	return full_rect;
134 }
135 }
136 
137 /* EN: This function make selection of directory by surface rectangle
138    So gs.path must specify the most deep directory which still
139    include surface rectangle.
140 
141    RU: Эта функция выбирает директорию в соответствии с прямоугольником,
142    который занимает surface. После выполнения этой функции gs.path
143    должен указывать на самую глубокую директорию которая ещё включает
144    прямоугольник surface.
145   */
146 unDE_Path_Finder_Flags
147 find_path(GlobalState gs, DbTxn txn, CoordinatesPlusScale surf, PathMnt path, 
148         DRect apply_rect, SortType sort = SortType.ByName, 
149         in int level = 0)
150 {
151     DRect surf_rect = surf.getRect();
152 
153 go_up:
154     bool up = false;
155     Dbt key, data;
156 
157     DirEntry de;
158     try
159     {
160         de = DirEntry(path);
161     }
162     catch (FileException e)
163     {
164         return unDE_Path_Finder_Flags.Try_Other_Directory;
165     }
166 
167     if (path in gs.lsblk)
168     {
169         string path0 = path.get_key(gs.lsblk);
170         key = path0;
171         auto res = gs.db_map.get(txn, &key, &data);
172         if (res == 0)
173         {
174             RectSize rectsize;
175             rectsize = data.to!(RectSize);
176             apply_rect = rectsize.rect(sort).apply(apply_rect);
177         }
178 	else
179 	{
180 		version(Windows)
181 		{
182 			if (path.length == 2)
183 			{
184 				DRect rect = get_drect_of_drives(gs, path);
185 				apply_rect = rect.apply(apply_rect);
186 			}
187 		}
188 
189 		{
190 		    // TODO: Created mount point, rescan up path
191 		}
192 	}
193     }
194 
195     try
196     {
197         path.update(gs.lsblk);
198     }
199     catch (Exception e)
200     {
201         return unDE_Path_Finder_Flags.Out;
202     }
203 
204     string path0 = path.get_key(gs.lsblk);
205     key = path0;
206     auto res = gs.db_map.get(txn, &key, &data);
207     version(Windows)
208     {
209     if (path == SL) res = 0;
210     }
211 
212     if (res == 0)
213     {
214         up = false;
215         RectSize rectsize;
216 	version(Windows)
217 	{
218 		if (path == SL) 
219 		{
220 			DRect full_rect = DRect(0, 0, 1024*1024, 1024*1024);
221 			rectsize = RectSize(full_rect, full_rect, full_rect);
222 		}
223 		else
224 			rectsize = data.to!(RectSize);
225 	}
226 	else
227 	{
228 		rectsize = data.to!(RectSize);
229 	}
230         rectsize.rect(sort) = rectsize.rect(sort).apply(apply_rect);
231         auto wtdwpbr = what_to_do_with_path_by_rectangle(gs, surf_rect,
232                     rectsize, path, apply_rect, sort, level);
233         //writefln("%s - %s", path, wtdwpbr);
234         final switch (wtdwpbr)
235         {
236             case unDE_Path_Finder_Flags.Go_Up:
237                 path = gs.path = PathMnt(SL);
238                 apply_rect = gs.apply_rect = DRect(0, 0, 1024*1024, 1024*1024);
239                 gs.sort = SortType.ByName;
240                 goto go_up;
241 
242             case unDE_Path_Finder_Flags.Go_Down:
243                 if (!de.isSymlink && de.isDir)
244                 {
245                     string[] paths;
246 
247                     try
248                     {
249 			    //writefln("Go Down?");
250 			bool done = false;
251 		        version(Windows)
252 		        {
253 			    if (path == SL) 
254 			    {
255 			    //writefln("This way?");
256 				foreach(char c; 'A'..'Z'+1)
257 				{
258 				    string name = c ~ ":";
259 				    if ( name in gs.lsblk )
260 				    {
261 					auto r = find_path(gs, txn, surf, path.next(name),  
262 						rectsize.rect(sort), rectsize.sort, level+1);
263 					if (r == unDE_Path_Finder_Flags.Out) return r;
264 				    }
265 				}
266 				done = true;
267 			    }
268 			}
269 
270 			if (!done)
271 			{
272 			    //writefln("This way!");
273 			    foreach (string name;
274 			            dirEntries(path, SpanMode.shallow))
275 			    {
276 				auto r = find_path(gs, txn, surf, path.next(name),  
277 				        rectsize.rect(sort), rectsize.sort, level+1);
278 				if (r == unDE_Path_Finder_Flags.Out) return r;
279 			    }
280 			}
281                     } catch (FileException e)
282                     {
283                     }
284                 }
285                 break;
286 
287             case unDE_Path_Finder_Flags.Out:
288                 if (level == 0 && path != SL)
289                     goto case unDE_Path_Finder_Flags.Go_Up;
290                 return unDE_Path_Finder_Flags.Out;
291 
292             case unDE_Path_Finder_Flags.Try_Other_Directory:
293                 if (level == 0 && path != SL)
294                     goto case unDE_Path_Finder_Flags.Go_Up;
295                 return unDE_Path_Finder_Flags.Try_Other_Directory;
296         }
297     }
298     else
299     {
300         //throw new Exception("No " ~ path ~ " entry");
301     }
302 
303     return unDE_Path_Finder_Flags.Try_Other_Directory;
304 }