/**
 * Find short path.
 *
 */
function FindMaxFlow(graph, app)
{
    BaseAlgorithmEx.apply(this, arguments);
    this.message = g_selectStartVertexForMaxFlow;
    this.selectedObjects = {};
    this.selectedEdges = [];
    this.resetUpText = [];
    
    this.minEdgeSize = 2;
    this.maxEdgeSize = 12;
}


// inheritance.
FindMaxFlow.prototype = Object.create(BaseAlgorithmEx.prototype);
// First selected.
FindMaxFlow.prototype.firstObject = null;
// Second selected.
FindMaxFlow.prototype.secondObject = null;
// Path
FindMaxFlow.prototype.selectedEdges = null;


FindMaxFlow.prototype.getName = function(local)
{
    return g_MaxFlowName; //local == "ru" ? "Поиск максимального потока" : "Find Maximum flow";
}

FindMaxFlow.prototype.getId = function()
{
    return "OlegSh.FindMaxFlow";
}

// @return message for user.
FindMaxFlow.prototype.getMessage = function(local)
{
    return this.message;
}

FindMaxFlow.prototype.result = function(resultCallback)
{
    if (this.firstObject && this.secondObject)
    {
        this.outResultCallback = function (result ) { resultCallback(result); };
        self = this;
        this.CalculateAlgorithm("mfpr", 
            [
                {name: "source", value: this.firstObject.id},
                {name: "drain", value: this.secondObject.id}
            ],
            function (pathObjects, properties, results)
            {
                self.resultCallback(pathObjects, properties, results);
            });
    }
    return null;
}

FindMaxFlow.prototype.resultCallback = function(pathObjects, properties, results)
{
    var outputResult = {};
    outputResult["version"] = 1;
    
    this.pathObjects = pathObjects;
    this.properties = properties;
    
    var bFound = results.length > 0 && results[0].value < 1E5 && (results[0].type == 1 || results[0].type == 2) && results[0].value * 1 > 0.0;
    
    var maxFlow = results[0].value * 1;
    
    if (bFound)
    {
        this.selectedObjects = {};

        var defaultDiameter = (new EdgeModel()).width;

        var avgFlow = 0;
        var countEdges = 0;
        
        for (var i = 0; i < pathObjects.length; i++)
        {
            if (pathObjects[i] instanceof BaseEdge)
            {
                avgFlow += properties[pathObjects[i].id]["flowValue"] * 1;
                countEdges += 1;
            }
        }
        avgFlow = avgFlow / countEdges;
        
        for (var i = 0; i < pathObjects.length; i++)
        {
            if (pathObjects[i] instanceof BaseEdge)
            {
                this.selectedObjects[pathObjects[i].id] = 1;
                var flow = properties[pathObjects[i].id]["flowValue"] * 1;
                if (pathObjects[i].useWeight || flow != pathObjects[i].GetWeight())
                {
                    pathObjects[i].text = flow + " / " + pathObjects[i].GetWeight();
                }
                if (!pathObjects[i].isDirect)
                {
                    if (parseInt(properties[pathObjects[i].id]["backToFront"]) > 0)
                    {
                        pathObjects[i].arrayStyleStart = "arrow";  
                    }
                    else
                    {
                         pathObjects[i].arrayStyleFinish = "arrow";     
                    }
                }
                
                pathObjects[i].model.width = Math.max(Math.min((flow / avgFlow) * defaultDiameter, this.maxEdgeSize), this.minEdgeSize);
            }
        }
        this.selectedEdges = pathObjects;
    
        this.message = g_maxFlowResult.replace("%1", (maxFlow).toString()).replace("%2", this.firstObject.mainText).replace("%3", this.secondObject.mainText);
        
        this.selectedObjects[this.secondObject.id] = 3;
        this.selectedObjects[this.firstObject.id]  = 1;
        
        this.secondObject.upText = g_sinkVertex;
        this.resetUpText.push(this.secondObject);
    }
    else
    {
        this.message = g_flowNotExists.toString().replace("%1", this.firstObject.mainText).replace("%2", this.secondObject.mainText);
    }
    this.secondObject = null;
    this.firstObject = null;
    
    this.outResultCallback(outputResult);
}

FindMaxFlow.prototype.selectVertex = function(vertex)
{
	this.pathObjects = null;
	this.shortDist = null;
    
    if (this.firstObject)
    {
        this.message      = g_processing;
        this.secondObject = vertex;
        this.selectedObjects = [];
    }
    else
    {
        this.restore();
        
        this.firstObject = vertex;
        this.secondObject = null;
        this.selectedObjects = {};
        this.message = g_selectFinishVertexForMaxFlow;
        this.firstObject.upText  = g_sourceVertex;
        this.resetUpText.push(this.firstObject);
    }

    return true;
}

FindMaxFlow.prototype.deselectAll = function()
{
    this.firstObject  = null;
    this.secondObject = null;
    this.selectedObjects = {};
    this.message = g_selectStartVertexForMaxFlow;
    this.restore();
    return true;
}

FindMaxFlow.prototype.instance = function()
{
    return false;
}

FindMaxFlow.prototype.getObjectSelectedGroup = function(object)
{
    return (object.id in this.selectedObjects) ? this.selectedObjects[object.id] : ((object == this.firstObject || object == object.secondObject) ? 1 : 0);
}

FindMaxFlow.prototype.getPriority = function()
{
    return -8.0;
}

// @return true, if you change resotry graph after use.
FindMaxFlow.prototype.wantRestore = function()
{
    return true;
}

// calls this method if wantRestore return true.
FindMaxFlow.prototype.restore = function()
{
    if (this.selectedEdges != null)
    {
        for (var i = 0; i < this.selectedEdges.length; i++)
        {
            if (this.selectedEdges[i] instanceof BaseEdge)
            {
                this.selectedEdges[i].text = "";
                this.selectedEdges[i].arrayStyleStart  = "";
                this.selectedEdges[i].arrayStyleFinish = "";
                this.selectedEdges[i].model.width = (new EdgeModel()).width;
            }
        }
        
        for (var i = 0; i < this.resetUpText.length; i++)
        {
            this.resetUpText[i].upText = "";
        }
    }
}

FindMaxFlow.prototype.IsSupportNegativeWeight = function()
{
    return true;
}


// Factory for connected components.
function CreateFindMaxFlow(graph, app)
{
    return new FindMaxFlow(graph, app)
}

// Gerister connected component.
RegisterAlgorithm (CreateFindMaxFlow);
