int	main()
{
	StructEquationSolve equationSolver;

	StructEquationSolve* pSolver;
	pSolver = &equationSolver;

	//equationSolver.solveEquation();
	//pSolver->solveEquation();
	StructEquationSolve&	citeSolver	= equationSolver; 

	citeSolver.solveEquation();


	StructEquationParameter	equationParamIn;
	StructEquationSolution	equationSolutionOut;
    
	string message = "Project Lesson08_Module_Function: print q to quit!";
	showPromptMessage( message );

	solveEquation(equationParamIn, equationSolutionOut);

/*
	inputParameter(equationParamIn);

	bool bValid = validateParameter(equationParamIn);

	if (bValid)
	{
		solveEquation(equationParamIn, equationSolutionOut);

		outputResult(equationSolutionOut);
	} 
	else
	{
		showPromptMessage("No Solutions!");
	}
*/

	return 0;
}
    void addBitangent(
        const real_t l,
        const real_t r,
        bool overestimate,
        const real_t epsilon
    )
    {
        bitangent bitan;
        bitan.start = a;
        bool start_fixed = b - a <= epsilon;
        real_t end = r;
        bool end_fixed = r - l  <= epsilon;

        if( start_fixed && end_fixed ) // if both fixed the secant will be used
        {

            real_t y1 = ( *this )( bitan.start );
            real_t y2 = curve( end );
            real_t slope = ( y2 - y1 ) / ( end - bitan.start );

            //this case happens when the function is concave and should be underestimated
            //or it is convex and should be overestimated. Then the secant of the endpoints is
            //used as estimator
            bitan.line.setCoeff( 1, slope );
            bitan.line.setCoeff( 0, y2 - slope * r );
            addBitangent( end, bitan );
            return;
        }

        auto curveDeriv = differentiate<1>( curve );
        SimplePolynomial< 0, real_t > rhs;

        real_t y1 = ( *this )( bitan.start );
        real_t y2 = curve( end );

        //compute slope of line connecting the function values
        real_t slope = ( y2 - y1 ) / ( end - bitan.start );

        while( 1 )
        {
            //check for termination, i.e. slope matches curve slope at both parts
            //or one of the parts is fixed
            if( ( start_fixed || std::abs( curveDeriv( bitan.start ) - slope ) <= epsilon ) &&
                    ( end_fixed || std::abs( curveDeriv( end ) - slope ) <= epsilon ) )
            {
                bitan.line.setCoeff( 1, slope ); // use current slope
                bitan.line.setCoeff( 0, y2 - end * slope ); // compute constant value using  y2 = end*slope+c <=> c = y2 - end*slope
                //add tangent
                addBitangent( end, bitan );
                return;
            }

            //if not terminating compute new endpoints for tangent
            rhs.setCoeff( 0, slope );

            if( !start_fixed )
            {
                bool changed = false;
                std::vector<real_t> sol = curveDeriv.solveEquation( rhs, a, b, epsilon );
                bool nosol = true;

                //filter out solutions that are cut off by current tangents
                //after that there should be 1 solution or 0.
                for( auto i = sol.begin(); i != sol.end(); ++i )
                {
                    interval_t interv = this->findInterval( *i );

                    if( interv == bitangents.end() )
                    {
                        nosol = false;

                        if( bitan.start != *i )
                        {
                            bitan.start = *i;
                            changed = true;
                        }

                        break;
                    }
                }

                if( nosol ) // if there was no solution, i.e. all solutions were cut off by current tagents we choose an interval endpoint
                {
                    real_t newstart;

                    if( curve( a ) - a * slope > curve( b ) - b * slope )
                        newstart = overestimate ? a : b;
                    else
                        newstart = overestimate ? b : a;

                    if( newstart != bitan.start )
                    {
                        changed = true;
                        bitan.start = newstart;
                    }
                }

                if( changed )
                {
                    y1 = ( *this )( bitan.start );
                    slope = ( y2 - y1 ) / ( end - bitan.start );
                }
                else
                {
                    start_fixed = true;
                }
            }

            if( !end_fixed )
            {
                bool changed = false;
                //should always have size 1 or 0 since curve is convex/concave in [l,r]
                std::vector<real_t> sol = curveDeriv.solveEquation( rhs, l, r, epsilon );

                if( sol.empty() )
                {
                    real_t newend;

                    if( curve( l ) - slope * l > curve( r ) - slope * r )
                        newend = overestimate ? l : r;
                    else
                        newend = overestimate ? r : l;

                    if( newend != end )
                    {
                        end = newend;
                        changed = true;
                    }
                }
                else
                {
                    if( end != sol[0] )
                    {
                        end = sol[0];
                        changed = true;
                    }
                }

                if( changed )
                {
                    y2 = curve( end );
                    slope = ( y2 - y1 ) / ( end - bitan.start );
                }
                else
                {
                    end_fixed = true;
                }
            }
        }
    }