//total file count
var totalFileNum = 0;
var doneFileNum = 0;
var maxLimit = 50;

var pathStack = [];
var excludeExtReg=/\.(jpg|jpeg|png|gif|bmp|ico|ttf|eot|woff|zip|rar|mp4)$/i;

//timeout instance
var timeInstance = null;

function doStackWork(reg,cb,replaceCon){
    var paths = pathStack.splice(0,maxLimit);
    var i;
    if( paths.length ){
        for(i=0;i<paths.length;i++){
            replaceCon ? _replace(paths[i],reg,cb,replaceCon) : _find(paths[i],reg,cb);
        }
        timeInstance = setTimeout(doStackWork,5);
    }else{
        cb(null);
        clearTimeout(timeInstance);
    }
}

function find(path,type,reg,exclude,func){
    findAction(path,type,reg,exclude,func);
}

function replace(path,type,reg,exclude,replaceCon,func){
    findAction(path,type,reg,exclude,func,replaceCon);
}

function findAction(path,type,reg,exclude,func,replaceCon){
    reg = new Function("return "+reg)();
    if( exclude.trim() ){
        exclude = new RegExp('^('+exclude.split(' ').join('|')+')$','i');
    }else{
        exclude = null;
    }
    
    var message = [];
    var cb = function(result){
        doneFileNum ++;
        if( result ){
            message.push(result);
            if( message.length == maxLimit ){
                func({data:message,total:totalFileNum,done:doneFileNum});
                message = [];
            }else if( totalFileNum == doneFileNum && message.length ){
                func({data:message,total:totalFileNum,done:doneFileNum});
                func({EOF:true});
            }
        }else if( result === null & doneFileNum == 1 ){
            func({data:message,total:totalFileNum,done:doneFileNum});
        }
    };
    
    var typeReg=null;
    if( type ){
        typeReg = new Function( "return /\\.("+type.split(' ').join('|')+")$/i" )();
    }
    _search(path,typeReg,exclude,cb);
    
    if( replaceCon ){
        doStackWork = doStackWork.bind(null,reg,cb,replaceCon);
    }else{
        doStackWork = doStackWork.bind(null,reg,cb);
    }
    
    setTimeout(doStackWork,50);
}

function getPathSplitChar(){
    return /^win/i.test(process.platform) ? '\\' : '/';
}

function _search(path,reg,exclude,func){
    var fs = require('fs');
    fs.readdir(path,function(error,files){
        if( error ){
            //add file number
            totalFileNum ++;
            func({success:0});
            return;
        }
        
        var rt = [],filename,tempRt,stat,newPath;
        //add file number
        totalFileNum += files.length;
        
        for( var i=0,len=files.length;i<len;i++){
			filename = files[i];
			newPath = path+filename;
			stat = fs.statSync(newPath);
			//if it's the directory
            if( stat.isDirectory() ){
                //minus file number
                totalFileNum--;
                if( !exclude || !exclude.test(filename) ){
                    _search(newPath+getPathSplitChar(),reg,exclude,func);  
                }
            }else if( !excludeExtReg.test(filename) && ( !reg || reg.test(filename) ) ){
                pathStack.push(newPath);
            }else{
                totalFileNum --;
            }
		}
    });
}
  
function _replace(path,reg,func,replaceCon){  
    var fs = require('fs');
    fs.readFile(path,function(error,con){
        if( error ){
            func({success:0});
            return;
        }
        
        con = con.toString();
        var match=[],item;
        var arr,prevFlagment,nextFlagment,row,column,line;
        
        if( con ){
            con = con.replace(reg,function(rt,index,all){
                arr = all.slice(0,index).split('\n');
                prevFlagment = arr.pop();
                column = prevFlagment.length;
                row = arr.length+1;
                
                prevFlagment = prevFlagment.replace(/^\s+|\s+$/g,' ');
                nextFlagment = all.slice(index+rt.length).split('\n').shift().replace(/^\s+|\s+$/g,' ');
                
                if( prevFlagment.length > 100 ){
                    line = _htmlspecialchars( '...'+ prevFlagment.slice(-50) ) + '<span class="ace_storage ace_type">'+replaceCon+'</span>'+ _htmlspecialchars( nextFlagment.slice(0,50)+'...' );
                }else if( nextFlagment.length > 100 ){
                    line = _htmlspecialchars( prevFlagment ) + '<span class="ace_storage ace_type">'+replaceCon+'</span>' + _htmlspecialchars( nextFlagment.slice(0,50) );
                }else{
                    line = _htmlspecialchars( prevFlagment ) + '<span class="ace_storage ace_type">'+replaceCon+'</span>' + _htmlspecialchars( nextFlagment );
                }
            
                match.push({
                    row:row,
                    column:column,
                    line:line
                });
                
                return replaceCon;
            });
            
            fs.writeFile(path,con,function(error){
                if( error ){
                    func({success:0});
                }else{
                    func({success:1,match:match,path:path});
                }
            });
        }else{
            func({success:0});
        }
        
    });
}

function _find(path,reg,func){
    var fs = require('fs');
    fs.readFile(path,function(error,con){
        if( error ){
            func({success:0});
            return;
        }
        
        con = con.toString();
        var match=[],item;
        var arr,prevFlagment,nextFlagment,row,column,line;
        
        if( con ){
            con.replace(reg,function(rt,index,all){
                arr = all.slice(0,index).split('\n');
                prevFlagment = arr.pop();
                column = prevFlagment.length;
                row = arr.length+1;
                
                prevFlagment = prevFlagment.replace(/^\s+|\s+$/g,' ');
                nextFlagment = all.slice(index+rt.length).split('\n').shift().replace(/^\s+|\s+$/g,' ');
                
                if( prevFlagment.length > 100 ){
                    line = _htmlspecialchars( '...'+ prevFlagment.slice(-50) ) + '<span class="ace_storage ace_type">'+rt+'</span>'+ _htmlspecialchars( nextFlagment.slice(0,50)+'...' );
                }else if( nextFlagment.length > 100 ){
                    line = _htmlspecialchars( prevFlagment ) + '<span class="ace_storage ace_type">'+rt+'</span>' + _htmlspecialchars( nextFlagment.slice(0,50) );
                }else{
                    line = _htmlspecialchars( prevFlagment ) + '<span class="ace_storage ace_type">'+rt+'</span>' + _htmlspecialchars( nextFlagment );
                }
            
                match.push({
                    row:row,
                    column:column,
                    line:line
                });
            });
        }
        
        func({success:1,match:match,path:path});
    });
}

function _htmlspecialchars(str){
    var s = "";
	if( str == undefined ){
		return 'undefined';
	}else if( typeof str == 'number' ){
		return str+'';
	}else if ( str.length == 0){
		return '';
	}

	for   (var i=0; i<str.length; i++)
	{
		switch (str.substr(i,1))
		{
			case "<": s += "&lt;"; break;
			case ">": s += "&gt;"; break;
			case "&": s += "&amp;"; break;
			case " ": s += " &nbsp;";break;
			case "\"": s += "&quot;"; break;
		   // case "\n": s += "<br>"; break;
			default: s += str.substr(i,1); break;
		}
	}
	return s;
}

// exports
module.exports = {find:find,replace:replace};