local ADDON_NAME = "BabRange";
local ADDON_VER = "1.04";
local ADDON_USAGE = "/br , /거리표시";

local INITIAL = {};
INITIAL.HEIGHT = 20;
INITIAL.COLOR1 = {0.2, 1, 0.2};
INITIAL.COLOR2 = {1, 0.5, 0.3};
INITIAL.ALPHA = 1;
INITIAL.POINTS = {"CENTER","UIParent","CENTER",0,-100};
INITIAL.OPTIONS = {0,0,0,0};

local NUM_OPTIONS = 4;
local UPDATE_RATE = .1;

local BabRangeSet = {};
local TargetType;
local curSet;
local D8,D28;
local adjust;

------------- Commom functions --------------------------------------------------------------------------
local function Print(msg, r, g, b, frame)
	if (not r) then r = 1.0; end
	if (not g) then g = 1.0; end
	if (not b) then b = 1.0; end
	if ( frame ) then
		if frame=="UIErrorsFrame" then
			UIErrorsFrame:AddMessage(msg,1,0.7,0.7,1,5);
		else
			frame:AddMessage(msg,r,g,b);
		end
	else
		if ( DEFAULT_CHAT_FRAME ) then
			DEFAULT_CHAT_FRAME:AddMessage(msg, r, g, b);
		end
	end
end

local function Notice(msg)
	Print(msg, 1,0.7,0.2);
end

local function Error(msg)
	Print(msg, nil, nil, nil, "UIErrorsFrame");
end

local function DB(msg)
	if not msg then
		msg = "Check!"
	end
	Print(msg, 0.5, 0.5, 0.5);
end

local function SetHook(myFunction, HookFunc, reverse)
	local oldFunction = getglobal(HookFunc);
	local newFunction;
	if not reverse then
		newFunction = function(arg1,arg2,arg3,arg4,arg5)
				local r={};
				r[1],r[2],r[3],r[4],r[5] = oldFunction(arg1,arg2,arg3,arg4,arg5);
				myFunction(arg1,arg2,arg3,arg4,arg5);
				if r[1] then
					return r[1],r[2],r[3],r[4],r[5]
				end
		end
	else
		newFunction = function(arg1,arg2,arg3,arg4,arg5)
				local r={};
				r[1] = myFunction(arg1,arg2,arg3,arg4,arg5);
				if r[1] then
					return
				end
				r[1],r[2],r[3],r[4],r[5] = oldFunction(arg1,arg2,arg3,arg4,arg5);
				if r[1] then
					return r[1],r[2],r[3],r[4],r[5]
				end
		end
	end
	setglobal(HookFunc, newFunction);
end

local function RegEvent(frame,events,unreg)
	if not unreg then
		for i,v in events do
			frame:RegisterEvent(v)
		end
	else
		for i,v in events do
			frame:UnregisterEvent(v)
		end
	end
end
local function Tooltip_ClearLines(tooltip)
	for i=1,(tooltip:NumLines()) do
		getglobal(tooltip:GetName().."TextRight"..i):SetText();
	end
	tooltip:ClearLines();
	tooltip:SetOwner(UIParent, "ANCHOR_NONE")
end

local function TableToArg(T)
	return T[1] , T[2] , T[3] , T[4] , T[5] , T[6]
end
--------------------------------------------------------------------------------------------------------
local function BabRange_GetRangedButton(button)
	local ubertooltips;
	if GetCVar("UberTooltips")=='1' then
		ubertooltips = true;
	else
		SetCVar("UberTooltips", 1, "USE_UBERTOOLTIPS");
	end

	local sb , lb = 1 , 120;
	if not button then
		BabRangeSet={};
	else
		sb , lb = button , button;
	end
	for i=sb,lb do
		if ActionHasRange(i) then
			Tooltip_ClearLines(BabRangeTooltip);
			BabRangeTooltip:SetAction(i);
			local spell = BabRangeTooltipTextLeft1:GetText();
			local range = BabRangeTooltipTextRight2:GetText();
			local temp = BabRangeTooltipTextLeft2:GetText();
			if not (spell=="생명력 집중" or spell=="동물 치료") then
				if not range then
					range = temp;
				end
				if range then
					temp = nil;
					for k in string.gmatch(range,"유효 거리 (.+)미터") do
						temp = k;
					end
					if temp then
						if UnitRace("player")=="타우렌" then
							if temp == '9' then
								temp = '5'
							end
						end
						BabRangeSet[i]={};
						BabRangeSet[i].range = temp
					end
				end
			end
		end
	end

	if not ubertooltips then
		SetCVar("UberTooltips", 0, "USE_UBERTOOLTIPS");
	end
end

local function BabRange_GetD8()
	local d8 = CheckInteractDistance("target", 2);
	if not d8 then 
		d8 = 0;
	end
	return d8.."";
end

local function BabRange_GetD28()
	local d28 = CheckInteractDistance("target", 4);
	if not d28 then 
		d28 = 0;
	end
	return d28.."";
end

local function BabRange_GetRangeSet()
	local set = "";
	for i,v in pairs(BabRangeSet) do
		local inRange = IsActionInRange( i );
		if not inRange then
			inRange = 2;
		end
		set=set..inRange;
	end
	
	return set;
end	

local function BabRange_Sort(TABLE)
	local n = #TABLE;
	local min,min_index;
	for i=1,n-1 do
		min=TABLE[i][1];
		min_index=i;
		for j=i+1,n do
			if min+0  > TABLE[j][1]+0 then
				min=TABLE[j][1];
				min_index=j;
			end
		end
		local temp=TABLE[min_index];
		TABLE[min_index]=TABLE[i];
		TABLE[i]=temp;
	end
	return TABLE;
end

local function BabRange_GetColor(overrange)
	if overrange then
		return TableToArg(BabRange_Saved.color2)
	else
		return TableToArg(BabRange_Saved.color1)
	end
end

local function BabRange_RangeAnalyze()
	if not curSet then
		BabRangeText:SetText();
		return
	end
	
	local TEMP={};
	local TEMP2={};
	local RANGE1={};
	local RANGE2={};
	local index = 0;
	
	for i,v in pairs(BabRangeSet) do
		index = index +1;
		local val = strsub(curSet,index,index);
		if val ~= '2' then
			if not TEMP2[v.range] then
				table.insert(TEMP,{[1]=v.range , [2]=val} );
				TEMP2[v.range]=1;
			end
		end
	end

	if not TEMP[1] then
		BabRangeText:SetText();
		return
	end
	-- TEMP : range & val

	for i,v in pairs(TEMP) do
		if not strfind(TEMP[i][1],'-') then
			local range = TEMP[i][1]+0;
			if range < 1000 then
				table.insert(RANGE1,TEMP[i]);
			end
		else
			table.insert(RANGE2,TEMP[i]);
		end
	end
	TEMP={};
	
	if RANGE2[1] then
		local MINMAX={};
		local minmax25;
		
		for i,v in pairs(RANGE2) do
			local max=gsub(v[1],"(%d)-(%d+)","%2");
			if max == "25" then
				minmax25 = v[2];
			else
				table.insert(MINMAX , {max,v[2]});
			end
		end

		for i,v in pairs(MINMAX) do
			local min,max;
			if D28 == '0' then
				if v[2] == '0' then
					min = '0';
					max = '0';
				else
					min = '0';
					max = '1';
				end
			else
				if v[2] == '0' then
					min = '1';
					max = '1';
				else
					min = '0';
					max = '1';
				end
			end
			if not TEMP2[v[1]] then
				table.insert( RANGE1, {[1]=v[1],[2]=max} );
				TEMP2[v[1]]=1;
			end
			if not TEMP2['8'] then
				table.insert( RANGE1, {[1]='8',[2]=min} );
				TEMP2['8']=1;
			end
		end
		
		if minmax25 then
			local min,max;
			if minmax25 == '1' then
				max = '1';
				min = '0';
			else
				if D8 == '0' then
					min = '0';
					max = '0';
				else
					min = '1';
					max = '1';
				end
			end
			if not TEMP2["25"] then
				table.insert( RANGE1, {[1]="25",[2]=max} );
				TEMP2["25"]=1;
			end
			if not TEMP2['8'] then
				table.insert( RANGE1, {[1]='8',[2]=min} );
				TEMP2['8']=1;
			end
		end
	end

	if BabRange_Saved.options[1] == 1 then
		if (TargetType=="friend" and BabRange_Saved.options[3]==1) or (TargetType=="enemy" and BabRange_Saved.options[4]==1) then
			if not TEMP2['8'] then
				table.insert( RANGE1, {[1]='8',[2]=D8} );
				TEMP2['8']=1;
			end
		end
	end
	if BabRange_Saved.options[2] == 1 then
		if (TargetType=="friend" and BabRange_Saved.options[3]==1) or (TargetType=="enemy" and BabRange_Saved.options[4]==1) then
			if not TEMP2['28'] then
				table.insert( RANGE1, {[1]='28',[2]=D28} );
				TEMP2['28']=1;
			end
		end
	end
	
	if not RANGE1[1] then
		BabRangeText:SetText();
		return
	end
		
	-- presentation	
	TEMP = BabRange_Sort(RANGE1);
	local SET="";
	for i,v in pairs(TEMP) do
		SET=SET..v[2];
	end

	--	DB(SET);
	-- error
	if strfind(SET,"10") then
		BabRangeText:SetText();
		return
	end

	local X=strfind(SET,"01");
	local overrange;
	local RANGE;
	
	if SET~="" then
		if X then
			RANGE = TEMP[X+1][1];
			if RANGE+0 > 50 then
				RANGE = TEMP[X][1];
				overrange = 1;
			end
		else
			if strfind(SET,"0") then
				RANGE = TEMP[strlen(SET)][1];
				overrange = 1;
			else
				RANGE = TEMP[1][1];
			end
		end
	end
	
	if not RANGE then
		BabRangeText:SetText();
		return
	end

	local msg = RANGE.." m";
	
	if overrange==1 then
		msg = msg.. " 이상";
	else
		msg = msg.. " 이내";
	end
	BabRangeText:SetText(msg);
	BabRangeText:SetTextColor(BabRange_GetColor(overrange));
	BabRangeText:SetAlpha(BabRange_Saved.alpha);
end

function BabRange_Update()
	curSet = BabRange_GetRangeSet();
	D8 = BabRange_GetD8();
	D28 = BabRange_GetD28();
	BabRange_RangeAnalyze();
end
--------------------------------------------------------------------------------------------------------
local function BabRangeToggle(id,arg)
	if arg==1 then
		BabRange_Saved[id] = 1;
		if id == 1 then
		
		elseif id == 2 then
			
		end
	else
		BabRange_Saved[id] = 0;
		if id == 1 then
			
		elseif id == 2 then
			
		end
	end
end

function BabRangeCheckButton_OnClick()
	if (this:GetChecked()) then
		BabRangeToggle(this:GetID() , 1);
	else
		BabRangeToggle(this:GetID() , 0);
	end
end

function BabRangeCheckButton_OnEnter()
	GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
	GameTooltip:SetText(this.tt)
end

function BabRangeCheckButton_OnLeave()
	GameTooltip:Hide();
end


--------------------------------------------------------------------------------------------------------
function BabRange_OpenColorPicker(id)
	local color;
	if id == 1 then
		color = BabRange_Saved.color1;
	else
		color = BabRange_Saved.color2;
	end
	
	ColorPickerFrame.func = BabRange_SetColor;
	ColorPickerFrame.cancelFunc = BabRange_CancelColor;
	ColorPickerFrame.br_id = id;
	ColorPickerFrame.br_color = color;
	ColorPickerFrame:SetColorRGB(TableToArg(color));
	ColorPickerFrame:Show();
end

function BabRange_SetColor()
	local r,g,b = ColorPickerFrame:GetColorRGB();
	local f;
	if ColorPickerFrame.br_id == 1 then
		f = BabRangeColorButton1_NormalTexture;
		BabRange_Saved.color1 = {r,g,b};
	else
		f = BabRangeColorButton2_NormalTexture;
		BabRange_Saved.color2 = {r,g,b};
	end
			
	f:SetVertexColor(r,g,b);
	BabRangeTextAdjust:SetTextColor(r,g,b);
end

function BabRange_CancelColor()
	local f;
	if ColorPickerFrame.br_id == 1 then
		f = BabRangeColorButton1_NormalTexture;
	else
		f = BabRangeColorButton2_NormalTexture;
	end
	f:SetVertexColor(TableToArg(ColorPickerFrame.br_color));
end

function BabRange_Alpha()
	local value = BabRangeColorAlpha:GetValue();
	if BabRangeColorAlpha:IsVisible() then
		BabRangeTextAdjust:SetAlpha(value);
		BabRange_Saved.alpha = value;
	end
	BabRangeColorAlphaText:SetText(floor(value*10)/10)
end

function BabRangeColor_Reset()
	BabRange_Saved.color1 = INITIAL.COLOR1;
	BabRange_Saved.color2 = INITIAL.COLOR2;
	BabRange_Saved.alpha = INITIAL.ALPHA;
	BabRangeColorAlpha:SetValue(BabRange_Saved.alpha);
	BabRangeTextAdjust:SetAlpha(BabRange_Saved.alpha);
	BabRangeColorButton1_NormalTexture:SetVertexColor( TableToArg(BabRange_Saved.color1) );
	BabRangeColorButton2_NormalTexture:SetVertexColor( TableToArg(BabRange_Saved.color2) );
end


-------------------------------------------------------------------------------------------------------
function BabRangeCheckButton_OnClick(id)
	if (this:GetChecked()) then
		BabRange_Saved.options[id] = 1;
	else
		BabRange_Saved.options[id] = 0;
	end
	BabRange_Update();
end

function BabRangeOption_Reset()
	BabRange_Saved.options = INITIAL.OPTIONS;
	for i=1, #INITIAL.OPTIONS do
		getglobal("BabRangeOptionCheck"..i):SetChecked(BabRange_Saved.options[i]);
	end
end
------------- onFoo functions --------------------------------------------------------------------------
local function BabRange_VariablesLoaded()
		
	if (not BabRange_Saved) or (BabRange_Saved.ver ~= ADDON_VER) then
		BabRange_Saved = {};
		BabRange_Saved.ver = ADDON_VER;
		
		BabRange_Saved.height = INITIAL.HEIGHT; 
		BabRange_Saved.locked = nil;

		BabRange:ClearAllPoints();
		BabRange:SetPoint(TableToArg(INITIAL.POINTS));

		BabRange_Saved.alpha = INITIAL.ALPHA;

		BabRange_Saved.color1 = INITIAL.COLOR1;
		BabRange_Saved.color2 = INITIAL.COLOR2;

		BabRange_Saved.options = INITIAL.OPTIONS;
	end

	if BabRange_Saved.locked then
		BabRange:EnableMouse(0);
		BabRange:SetBackdropBorderColor(1, 1, 1, 0);
	else
		BabRange:EnableMouse(1);
		BabRange:SetBackdropBorderColor(1, 1, 1, 0.5);
	end

	if BabRange_Saved.points then
		BabRange:SetPoint(TableToArg(BabRange_Saved.points));
	end

	local path, _ , flag = BabRangeText:GetFont();
	BabRangeText:SetFont(path, BabRange_Saved.height , flag);

	BabRangeColorAlpha:SetValue(BabRange_Saved.alpha);
	BabRangeText:SetAlpha(BabRange_Saved.alpha);

	BabRangeColorButton1_NormalTexture:SetVertexColor( TableToArg(BabRange_Saved.color1) );
	BabRangeColorButton2_NormalTexture:SetVertexColor( TableToArg(BabRange_Saved.color2) );

	for i=1, #INITIAL.OPTIONS do
		getglobal("BabRangeOptionCheck"..i):SetChecked(BabRange_Saved.options[i]);
	end
end

local function BabRange_Adjust()
	BabRange:ClearAllPoints();
	BabRange:SetPoint("CENTER","UIParent","CENTER",0,-100);
	
	BabRange:EnableMouse(1);
	BabRange:SetBackdropBorderColor(1, 1, 1, 0.5);
	BabRange_Saved.locked = nil;
	
	local path, _ , flag = BabRangeText:GetFont();
	BabRangeText:SetFont(path, INITIAL.HEIGHT , flag);
	BabRange_Saved.height = INITIAL.HEIGHT; 
end

local function BabRange_SlashCommand(msg)
	if msg then
		local msg = strlower(msg);
		if msg == "option" or msg == "옵션" then
			BabRangeOption:Show();
			return;
		elseif msg == "adjust" or msg == "조절" then
			BabRange_Adjust();
			return;
		end
	end
	
	Notice("** BabRange **");
	Notice("/거리표시 옵션 (/br option) : 옵션창열기");
	Notice("/거리표시 조절 (/br adjust) : 글씨조절하기");
end


function BabRange_OnLoad()
	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("PLAYER_TARGET_CHANGED");
	this:RegisterEvent("CHARACTER_POINTS_CHANGED");
	this:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
		
	this.update = UPDATE_RATE;		

	SlashCmdList["BABRANGE"] = BabRange_SlashCommand;
	SLASH_BABRANGE1 = "/br";
	SLASH_BABRANGE2 = "/BR";
	SLASH_BABRANGE3 = "/거리표시";

	this.addon_name = ADDON_NAME;
	this.addon_ver = ADDON_VER;
end

function BabRange_OnEvent(event)
	if event == "VARIABLES_LOADED" then
		Notice(ADDON_NAME.." ver."..ADDON_VER.." Loaded. ( Usage: ".. ADDON_USAGE .." )");
		this.load = 1;
	elseif event == "PLAYER_TARGET_CHANGED" then
		if not this.getbutton then
			this.getbutton = 1;
			BabRange_GetRangedButton();
		end
		if UnitCanAttack("player", "target") then
			TargetType = "enemy";
		else
			TargetType = "friend";
		end
		if UnitIsVisible("target") and not UnitIsUnit("target" ,"player") then
			this.enable = 1;
			BabRange_Update();
		else
			this.enable = nil;
			BabRangeText:SetText();
		end
	elseif event == "CHARACTER_POINTS_CHANGED" then
		BabRange_GetRangedButton();
		BabRange_Update();
	elseif event == "ACTIONBAR_SLOT_CHANGED" then
		if BabRangeSet[arg1] then
			BabRangeSet[arg1]=nil;
		end
		if ActionHasRange(arg1) then
			BabRange_GetRangedButton(arg1);
		end
	end

end

function BabRange_OnUpdate(elapsed)
	if this.load then
		this.load = this.load - elapsed;
		if this.load < 0 then
			this.load = nil;
			BabRange_VariablesLoaded();
		end
		return
	end
	
	if this.enable then
		local d8 = BabRange_GetD8();
		local d28 = BabRange_GetD28();
		local set = BabRange_GetRangeSet();	
		if (set ~= curSet) or (d8 ~= D8) or (d28 ~= D28) then
			curSet = set;
			D8 = d8;
			D28 = d28;
			BabRange_RangeAnalyze();
		end
	end
end


function BabRange_OnEnter()
	GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT", 0, 0);
	GameTooltip:SetText("BabRange");
	GameTooltip:AddLine("좌클릭 : 창이동\n우클릭 : 창고정\n마우스휠 : 크기조절\nShift+클릭 : 색조절",1,1,1);
	GameTooltip:Show();
end

function BabRange_OnMouseDown()
	this:SetBackdropBorderColor(1, 1, 1, 0);
	this:EnableMouse(0);
	BabRange_Saved.locked = 1;
end

function BabRange_OnMouseUp()
	BabRange_Saved.points = {BabRange:GetPoint()};
end

function BabRange_OnMouseWheel()
	if not BabRange_Saved.locked then
		local path, height , flag = BabRangeText:GetFont();
		if arg1 == 1 then
			height = height+height*0.1
		else
			height = height-height*0.1
		end
		BabRangeText:SetFont(path , height , flag);
		BabRange_Saved.height = height;
	end
end
