"use strict";

var PATH = require ("path");
var meta = require ("meta-path");

var WIN = process.platform === "win32";

/*
	path.exists and path.existsSync are not added.
	The current node.js version dictates how to be backward compatible.
	Only new additions and bugs are fixed, that is, path.sep, path.delimiter and
	all the future additions are are added and path.normalize is fixed (cwd and
	Windows UNC paths).
	Wrappers for the fs module should add the exist function, for
	example:
	
	var path = require ("path");
	var fs = require ("fs");
	var fsWrapper = module.exports = {};
	fsWrapper.exists = fs.exists || path.exists;
	fsWrapper.existsSync = fs.existsSync || PATH.existsSync;
*/

var path = module.exports = {};

path.basename = PATH.basename;
path.delimiter = WIN ? ";" : ":";
path.dirname = PATH.dirname;
path.extname = PATH.extname;

var fix = function (p){
	var i = p.indexOf (":") + 1;
	var fix = meta.fix ();
	return path.normalize (p.substring (0, i) + (fix ? fix + path.sep : "") +
			p.substring (i));
};

path.get = function (p){
	if (!path.isRelative (p)) return path.normalize (p);
	var isHome = path.isHome (p);
	if (!WIN && isHome){
		return path.resolve (p);
	}else if (WIN && isHome){
		return p;
	}
	return fix (p);
};

//isAbsolute, isNetwork and isRelative are faster than meta-data's equivalent
//functions

path.isAbsolute = (function (){
	if (WIN){
		return function (p){
			var i = p.indexOf (":") + 1;
			return p[i] === "/" || p[i] === "\\";
		};
	}
	return function (p){
		return p[p.indexOf (":") + 1] === "/";
	};
})();

path.isHome = function (p){
	return p[0] === "~";
};

path.isNetwork = (function (){
	if (WIN){
		return function (p){
			var i = p.indexOf (":") + 1;
			return (p[i] === "/" && p[i + 1] === "/") ||
					(p[i] === "\\" && p[i + 1] === "\\");
		};
	}
	return function (p){
		var i = p.indexOf (":") + 1;
		return p[i] === "/" && p[i + 1] === "/";
	};
})();

path.isRelative = (function (){
	if (WIN){
		return function (p){
			var i = p.indexOf (":") + 1;
			return p[i] !== "/" && p[i] !== "\\";
		};
	}
	return function (p){
		return p[p.indexOf (":") + 1] !== "/";
	};
})();

path.isRoot = (function (){
	if (WIN){
		return function (p){
			var i = p.indexOf (":") + 1;
			if (i) p = p.substring (i);
			return (p === "/" || p === "//" || p === "\\" || p === "\\\\");
		};
	}
	return function (p){
		var i = p.indexOf (":") + 1;
		if (i) p = p.substring (i);
		return (p === "/" || p === "//");
	};
})();

path.join = function (){
	//Join cannot be wrapped because internally it normalizes the joined
	//path and cannot be fixed a normalized path; meta-path must receive the
	//original path. Also, the Windows join is bugged for UNC paths.
	var paths = Array.prototype.slice.call (arguments, 0);
	var data = meta (paths.filter (function (p){
		return p && typeof p === "string";
	}).join ("/"));
	return data.normalized;
};

path.normalize = function (p){
	return meta (p).normalized;
};

path.prefix = function (p){
	return p.substring (0, p.indexOf (":") + 1);
};

path.realpath = function (p){
	return path.resolve (p);
};

//Relative doesn't need to be wrapped because it doesn't call to normalize
path.relative = PATH.relative;

path.removePrefix = function (p){
	var i = p.indexOf (":") + 1;
	return i ? p.substring (i) : p;
};

path.resolve = function (){
	var paths = Array.prototype.slice.call (arguments, 0);
	//Prepends a possible fix, no matter if the path to resolve is absolute
	//because the fix will be discarded
	var f = meta.fix ();
	if (f){
		paths.unshift (f);
	}
	var args = [];
	var home = false;
	var absolute = false;
	var network = false;
	var c;
	var s;
	var index;
	var prefixNetwork;
	//Filters all the paths starting with ~ and leaves only the rightmost
	for (var i=paths.length-1; i>= 0; i--){
		s = paths[i];
		//Removes a possible prefix if it's not a network path
		index = s.indexOf (":") + 1;
		if (!path.isNetwork (s)){
			//If it's not a network path removes the prefix
			if (index){
				s = s.substring (index);
			}
		}else{
			//If it's a network path removes the prefix but it's saved
			if (index){
				prefixNetwork = s.substring (0, index);
				s = s.substring (index);
			}
		}
		args.unshift (s);
		c = s[0];
		if (!WIN && c === "~"){
			home = true;
			break;
		}else if (c === "/" || (WIN && c === "\\")){
			if (s.length > 1){
				c = s[1];
				if (c === "/" || (WIN && c === "\\")){
					network = true;
					break;
				}
			}
			absolute = true;
			break;
		}
	}
	var p = PATH.resolve.apply (null, args);
	if (home){
		return process.env.HOME + p.substring (p.indexOf ("~") + 1);
	}else if (absolute){
		return p;
	}else if (network){
		if (WIN){
			p = p.substring (p.indexOf (":") + 1);
		}
		p = path.sep + p;
		return prefixNetwork ? prefixNetwork + p : p;
	}
	return p;
};

//Backward compatibility for versions prior to 0.8.x
path.sep = WIN ? "\\" : "/";
