(* ::Package:: *)

(* ::Chapter:: *)
(*prolog*)


Intercepts::usage = "Computes the intercepts of a function f(x)"


Needs["AlphaScannerFunctions`CommonFunctions`"]


Begin["`Private`"]


(* ::Chapter::Closed:: *)
(*main code*)


ClearAll[ContainsQ]
ContainsQ[expr_, form_, levelSpec_: {0, Infinity}]:= !FreeQ[expr, form ,levelSpec]
ContainsQ[form_]:= Function[expr, !FreeQ[expr, form]]


ClearAll[InterceptsScanner]
InterceptsScanner[expr_, depVars_, indepVars_] := Quiet @ Module[
	{
		e, indepvars, depvars,
		vars, axesvars, explicitQ = (preprocessUserInput[expr,"NoFail"->True]=!=expr || FreeQ[{expr},Equal]),
		res, axes="All"
	}, 
	(*bug 262799*)
	If[ContainsQ[Simplify[Expand[expr]],Complex[__]|I], Return[$Failed]];
	
	(* See bug 258235. *)
	With[{vl = VarList[expr]},
		If[Length[vl] == 1 && MatchQ[axes, _Symbol] && vl =!= {axes},
			If[FreeQ[expr, Equal],
				Return[InterceptsScanner[axes == expr, axes]]
			];
			If[MatchQ[expr, _Symbol[Symbol["x"]] == _] && axes === Symbol["y"],
				Return[InterceptsScanner[expr, axes]]
			];
		];
	];
	
	{e, indepvars, depvars} = InterceptsInitialProcess[Unevaluated@expr, axes, explicitQ];
	depvars = depVars;
	indepvars = indepVars;

	vars = DeleteDuplicates@Flatten[{indepvars,depvars}]; 
	DebugPrint["preprocessUserInputHeld[expr]",preprocessUserInputHeld[expr],"vars",{indepvars,depvars}];
	DebugPrint["vars",vars, "explicitQ",explicitQ];
	
	axesvars = If[Length[depvars]>1 (*parametric func*),depvars,vars];
	DebugPrint["vars",vars,"axesvars",axesvars];

	res = Chop/@GetIntercepts[e,vars,axesvars,#]&/@axesvars;
	res = res /.{ConditionalExpression[a_?NumericQ,Element[C[1],Integers]]:>a}/.{c:ConditionalExpression[_,Element[C[1],Integers]] :> (If[NumericQ[#],#,c]&@(Assuming[#[[2]],Simplify[#[[1]]]]&[List@@c]))}
]


(* ::ResourceHiddenPageBreak:: *)
(**)


Options[InterceptsInitialProcess] = {"CoordinateSystem" -> Automatic, "ShowArcLengthPlot" -> "dontcare"};
InterceptsInitialProcess[e_, axes_, explicitQ_, opt:OptionsPattern[]] := Module[
	{
		origexpr, expr, vars, depvars, fn
	}, 
	DebugPrint["InterceptsInitialProcess",Hold@e];
	origexpr = e /. {PopupLink[a_,__]->a} /. {a_} :> a;
	origexpr = If[Head[origexpr]===And,List@@origexpr,origexpr];
	expr = If[MatchQ[origexpr, HoldPattern[Equal[{__},{__}]]], Thread[origexpr], origexpr];
	
	fn = preprocessUserInput[expr, "NoFail"->True]; (*7/10/12: we dont want implicit functions to fail - pbarendse*) 
	
	DebugPrint["fn",fn];
	If[ContainsQ[fn, $Failed], Return[]];
	
	{vars, depvars} = chooseVariables[##, "ReturnDependent" -> True(*, "PossibleVariable"->axes*)]&[Unevaluated@e,fn];
	vars = "Independents" /. vars;
	depvars = "Dependents" /. depvars;
	
	
	If[vars==={}, vars = Select[{Symbol["x"],Symbol["t"],Symbol["u"],Symbol["y"],Symbol["v"]},!MemberQ[depvars,#]&,1]]; DebugPrint[vars,depvars];
	
	If[Head[depvars] =!= List, depvars = {depvars}];
	
	If[FreeQ[{expr},_Equal],expr=(If[Length[depvars]==1,depvars[[1]],depvars]==expr)]; 
	expr = If[MatchQ[expr, HoldPattern[Equal[{__},{__}]]], Thread[expr], expr]/.{(a_?usersymbolQ)[__]:>a}; 
	 
	(* TODO: what if axes is not a member of vars? e.g. "x-intercept of y=t^2" *)
	If[axes =!= "All" && FreeQ[VarList[e],axes], (*what to do if the axis requested does not appear in the given expression? *)
		Which[
			VarList[preprocessUserInputHeld[e]]==={}, (*indep*)vars = {axes}, (*if function is constant, assume it is the indep. var. *)
			FreeQ[{e},Equal] || (explicitQ && ContainsQ[e,depvars[[1]][_]]), DebugPrint["assuming",depvars->{axes}]; expr=expr/.Thread[depvars->{axes}]; depvars = {axes},
			True, (*indep*)vars = Join[(*indep*)vars,{axes}]
		]
	];
	Return[{expr, vars, depvars}]
]


$singlesteptimelimit = 0.1;
(* the main intercepts function *)
GetIntercepts[input_, vars_, axesvars_, axes_] :=(
	TimeConstrained[Quiet@Refine@Solve[Flatten@{input, Thread[Complement[axesvars,{axes}]==0]}, vars, Method -> "Reduce"],$singlesteptimelimit,$Failed]
)

(* This is so that we can return intercepts within some domain through CustomScannerData. *)
GetIntercepts[input_, vars_, axesvars_, axes_, {a_, lo_, b_}] := 
	TimeConstrained[Quiet@Refine@Solve[Flatten@{input, Thread[Complement[axesvars,{axes}]==0], If[lo<b,lo <= a <= b, b <= a <= lo]}, vars, Method -> "Reduce"],$singlesteptimelimit,$Failed]

GetIntercepts[input_, vars_, axesvars_, axes_, Automatic] :=
	GetIntercepts[input, vars, axesvars, axes]

GetIntercepts[___] := $Failed


(* ::Chapter:: *)
(*epilog*)


End[]
