// Project Lab - NHTV Igad

#include "UnrealProject.h"
#include "SkillWidget.h"
#include "BaseSkillObject.h"
#include "SkillTreeObject.h"
#include "HexagonTile.h"
#include "CanvasPanel.h"
#include "Border.h"
#include "SkillTreeWidget.h"
#include "HexagonTile.h"
#include "WidgetLayoutLibrary.h"
#include "AbilityInfo.h"
#include "SizeBorder.h"
#include "MenuScreenBase.h"

int32 roundToNearestOdd(float a_in)
{
	return 2 * FMath::FloorToInt(a_in / 2) + 1;
}

int32 roundToNearestEven(float a_in)
{
	return 2 * FMath::FloorToInt(a_in / 2);
}

//Convert from Odd-q coordinate system to Cube.
FIntVector Oddq2Cube( FIntPoint in )
{
	int32 x = in.X;
	int32 z = int32( float( in.Y ) - float( in.X - ( in.X & 1 ) ) / 2.0f );
	int32 y = -x - z;
	return FIntVector( x, y, z );
}

//Convert from Cube coordinate system to Odd-q.
FIntPoint Cube2Oddq( FIntVector in )
{
	int32 x = in.X;
	int32 y = int32( float( in.Z ) + float( in.X - ( in.X & 1 ) ) / 2.0f );
	return FIntPoint( x, y );
}

//Convert from Even-q coordinate system to Cube.
FIntVector Evenq2Cube( FIntPoint in )
{
	int32 x = in.X;
	int32 z = int32( float( in.Y ) - float( in.X + ( in.X & 1 ) ) / 2.0f );
	int32 y = -x - z;
	return FIntVector( x, y, z );
}

//Convert from Cube coordinate system to Even-q.
FIntPoint Cube2Evenq( FIntVector in )
{
	int32 x = in.X;
	int32 y = int32( float( in.Z ) + float( in.X + ( in.X & 1 ) ) / 2.0f );
	return FIntPoint( x, y );
}

//Rotates a hexoganal position by the angle.
//The position must be in Cube coordinates.
//The angle must be in degrees.
FIntVector RotateHexPos( FIntVector in, float angle )
{
	while ( angle < 0 )
	{
		angle += 360;
	}
	while ( angle > 360 )
	{
		angle -= 360;
	}
	int32 steps = FMath::FloorToInt( angle / 60 );
	FIntVector result = in;
	for ( int32 i = 0; i < steps; i++ )
	{
		FIntVector tmp = FIntVector( -result.Z, -result.X, -result.Y );
		result = tmp;
	}
	return result;
}

//Rotates a hexoganal position by the angle.
//The position must be in Odd-q or Even-q coordinates.
//The OddQ boolean decides what coordinate system is used.
//The angle must be in degrees.
FIntPoint RotateHexPos( FIntPoint in, float angle, bool oddq )
{
	FIntVector cubeIn;
	if ( oddq )
		cubeIn = Oddq2Cube( in );
	else
		cubeIn = Evenq2Cube( in );

	FIntVector cubeOut = RotateHexPos( cubeIn, angle );

	FIntPoint Out;
	if ( oddq )
		Out = Cube2Oddq( cubeOut );
	else
		Out = Cube2Evenq( cubeOut );
	return Out;
}

void USkillWidget::PlaceOnGridIndex(FVector2D index)
{
	m_lastGridIndex = index /*+ FVector2D(1.5, 4) * RenderTransform.Scale.X*/;
	UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
	float viewportScale = UWidgetLayoutLibrary::GetViewportScale(parent);
	FVector2D topLeft = GetSkillTreePos();
	float scale = 32.0f  * (RenderTransform.Scale.X / 2);
	float XScale = (scale * 1.73205f);
	float YScale = scale;
	if(tmpSlot)
	{
		FVector2D result;
		result.X = index.X * XScale;
		result.X += topLeft.X;
		//result.X -= 2;
		result.Y = index.Y * YScale;
		result.Y += topLeft.Y;
		//result.Y += 14.5f;

		UCanvasPanelSlot* selfSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(this);
		selfSlot->SetPosition(result);

		placedPoints.SetNum(0);
		CheckPosition(m_lastGridIndex, &placedPoints);
		ChangeColor(GetShapeTypeColor());
	}
}

void USkillWidget::SetPlaced()
{
	m_dragable = true;
	m_placed = true;
}

void USkillWidget::UpdateSkill()
{
	m_hexagons.Empty();
	if ( !skillAsset )
	{
		//YWARNING( "No Skill Asset assigned to the Skill Widget." );
		SetVisibility( ESlateVisibility::Hidden );
		return;
	}
	SetVisibility(ESlateVisibility::SelfHitTestInvisible);
	TArray<UWidget*> widgets;
	WidgetTree->GetAllWidgets( widgets );
	UCanvasPanel* canvasPanel = NULL;

	FLinearColor color = GetShapeTypeColor();

	for ( int32 i = 0; i < widgets.Num(); i++ )
	{
		UHexagonTile* tmp = Cast<UHexagonTile>( widgets[i] );
		UCanvasPanel* tmpPanel = Cast<UCanvasPanel>( widgets[i] );
		if ( tmpPanel )	canvasPanel = tmpPanel;
		if ( !tmp ) continue;
		bool test = skillAsset->hexMap.Get( tmp->x, tmp->y );
		//tmp->SetColorAndOpacity( skillColor );
		m_hexagons.Push( tmp );
		if ( !test )
		{
			tmp->SetVisibility(ESlateVisibility::Hidden);
		}
		else
		{
			tmp->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
		}
	}
	if (!m_dragable)
	{
		UpdateLevel(0);
	}
	if ( canvasPanel )
	{
		m_canvasPanel = canvasPanel;
		UCanvasPanelSlot* slot = Cast<UCanvasPanelSlot>( canvasPanel->Slot );
		if ( slot )
		{
			m_slot = slot;
			float offset = 1.0f;
			float width = ( skillAsset->hexMap.width * 27.7128f ) + 4.2871f;
			FVector2D newSize = FVector2D(width, ( (skillAsset->hexMap.height * 32.0f) - offset ));
			m_slot->SetSize(newSize);
			//GWPRINT(L"Size of " + skillAsset->GetName() + L"(placed=" + m_placed + L") = " + newSize);
		}
		if ( m_dragable )
		{
			FVector2D transformPivot;
			transformPivot.X = ( float( skillAsset->pivot.X ) + 0.5f ) / float( skillAsset->hexMap.width );
			transformPivot.Y = ( float( skillAsset->pivot.Y ) + ( ( skillAsset->pivot.X & 1 ) ? 1.0f : 0.5f ) ) / float( skillAsset->hexMap.height );
			canvasPanel->SetRenderTransformPivot( transformPivot );
			//YPRINT( "Pivot: X=" + transformPivot.X + ", Y=" + transformPivot.Y );
		}
	}
	UCanvasPanel* mainCanvas = WidgetTree->FindWidget<UCanvasPanel>("Main_Canvas");
	if ( m_dragable )
	{
		//m_spacer->SetVisibility( ESlateVisibility::Hidden );
		SetRenderScale( parent->WidgetTree->FindWidget<UCanvasPanel>("Main_SkillTree")->RenderTransform.Scale );
	}
	else
	{
		//m_spacer->SetVisibility( ESlateVisibility::Visible );
		SetRenderScale( FVector2D( 1, 1 ) );
	}
	//float scale = RenderTransform.Scale.X - 1.0f;
	//float alignment = ( m_dragable ) ? (-scale * 0.5f) : 0.5f;
	//FVector2D alignment2D ( alignment, alignment );
	//tmpSlot->SetAlignment( alignment2D );

	if ( m_dragable && !m_controller )
	{
		FVector2D mousePos;
		UWidgetLayoutLibrary::GetMousePositionScaledByDPI( GetOwningPlayer(), mousePos.X, mousePos.Y );
		FVector2D skillPos;
		skillPos = mousePos - ( m_slot->GetSize() / 2 );
		UCanvasPanelSlot* tmpSlot2 = Cast<UCanvasPanelSlot>( Slot );
		if ( tmpSlot2 )
		{
			tmpSlot2->SetPosition( skillPos );
		}
		if(!m_placed)
			StartDragging();
		else
		{
			FVector2D position = GetViewportPos();
			FVector2D mousePos;
			UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
			m_offset = position - mousePos;
		}
		m_offset = -( ( m_slot->GetSize() * (RenderTransform.Scale.X / 2) ) / 2);
	}
	else if (m_controller)
	{
		StartDragging();
	}

	// Update color of hexagons
	UpdateSkillIcon();
	ChangeColor(color);
}

void USkillWidget::NativeConstruct()
{
	selectedEffect = -1;
	hovered = false;
	UpdateSkill();
	FIntPoint point( 0, 1 );
	FIntPoint a = RotateHexPos( point, 60, false );
	//YPRINT( "60: X:" + a.X + ", Y:" + a.Y );
	/*
	FIntPoint b = RotateHexPos( point, 120 );
	YPRINT( "120: X:" + b.X + ", Y:" + b.Y );
	FIntPoint c = RotateHexPos( point, 180 );
	YPRINT( "180: X:" + c.X + ", Y:" + c.Y );
	FIntPoint d = RotateHexPos( point, 240 );
	YPRINT( "240: X:" + d.X + ", Y:" + d.Y );
	FIntPoint e = RotateHexPos( point, 300 );
	YPRINT( "300: X:" + e.X + ", Y:" + e.Y );
	FIntPoint f = RotateHexPos( point, -60 );
	YPRINT( "-60: X:" + f.X + ", Y:" + f.Y );
	FIntPoint g = RotateHexPos( point, -120 );
	YPRINT( "-120: X:" + g.X + ", Y:" + g.Y );
	FIntPoint h = RotateHexPos( point, -180 );
	YPRINT( "-180: X:" + h.X + ", Y:" + h.Y );
	*/

	//m_border = WidgetTree->FindWidget<UBorder>("Border");
	//m_border->SetVisibility(ESlateVisibility::Hidden);

	Super::NativeConstruct();
}

void USkillWidget::NativeDestruct()
{
	Super::NativeDestruct();
}

void USkillWidget::UpdateSkillColor()
{
	FLinearColor color;
	if(m_dragging)
	{
		bool hover = CheckPosition(m_lastGridIndex);
		if(hover)
		{
			m_hovering = true;
			color = FLinearColor(0, 1, 0, 1);
			if(!GetSelectedEffectAbility())
				color = FLinearColor::Yellow;
		}
		else
		{
			m_hovering = false;
			color = FLinearColor(1, 0, 0, 1);
		}

	}
	else
	{
		color = GetShapeTypeColor();
	}
	ChangeColor(color);
}

void USkillWidget::UpdateSkillIcon()
{
	for(int32 i = 0; i < m_hexagons.Num(); i++)
	{
		if(m_hexagons[i]->material)
		{
			m_hexagons[i]->material->SetTextureParameterValue("Skill_Texture", m_skillIcon);
		}
	}
}

void USkillWidget::SetSelectedEffect(int32 effect)
{
	//UpdateSkill();

	if(effect >= 0 && effect < skillAsset->abilityEffects.Num())
	{
		selectedEffect = effect;

		// Set icon on hexagons
		UAbilityInfo* ability = skillAsset->abilityEffects[selectedEffect];
		if(ability)
		{
			m_skillIcon = ability->icon;
		}
	}

	// Update material
	UpdateSkillIcon();
	UpdateSkillColor();
}

class UAbilityInfo* USkillWidget::GetSelectedEffectAbility() const
{
	if(selectedEffect >= 0 && selectedEffect < skillAsset->abilityEffects.Num())
	{
		return skillAsset->abilityEffects[selectedEffect];
	}
	return nullptr;
}

void USkillWidget::Select()
{
	//if ( !m_spacer ) return;
	//m_spacer->SetBrushColor( FLinearColor( 1, 1, 1, 0.68f ) );
	//parent->DeselectOther( this );
	//m_selected = true;
	//UWidgetLayoutLibrary::GetMousePositionScaledByDPI( GetOwningPlayer(), m_mousedownPos.X, m_mousedownPos.Y );
}

void USkillWidget::Deselect()
{
	//if ( !m_spacer ) return;
	//m_spacer->SetBrushColor( FLinearColor( 0, 0, 0, 0.68f ) );
	//m_selected = false;
}

void USkillWidget::Remove()
{
	parent->RemoveSkill(this, placedPoints);
}

bool USkillWidget::RestartDragging()
{
	if (parent->draggingWidget)
		return false;

	parent->RemoveSkill(this, placedPoints);
	SetDragable(true, true);
	SetUserFocus(GetOwningPlayer());

	parent->draggingWidget = this;

	m_hovering = true;
	ChangeColor(FLinearColor(0, 1, 0, 1));
	return true;
}

void USkillWidget::StartDragging()
{
	if(!m_dragging && parent->draggingWidget == nullptr && parent->IsInteractive())
	{
		m_dragging = true;
		FVector2D position = GetViewportPos();
		FVector2D mousePos;
		UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
		m_offset = position - mousePos;
		if(m_placed) parent->RemoveSkill(this, placedPoints);
		m_placed = false;
		parent->StartDragging(this);
		OnStartDragging();
	}
	//YPRINT( "Start... (X: " + position.X + ", Y: " + position.Y + ")" );
}

bool USkillWidget::PlaceSkill()
{
	// Check if we have selected a valid effect
	bool canPlace = true;
	bool effectAssigned = GetSelectedEffectAbility() != nullptr;
	//if(m_controller && !effectAssigned)
	//	canPlace = false;
	if(skillAsset->abilityEffects.Num() == 0)
	{
		GERROR("Skill has no ability effects assigned, " + skillAsset->GetName());
		canPlace = false;
	}

	TArray<FIntPoint> points;
	placedPoints.Empty();
	if(!CheckPosition(m_lastGridIndex, &points))
		canPlace = false;

	if(canPlace)
	{
		placedPoints = points;
		parent->AddSkill(this, points);
		m_placed = true;
		ChangeColor(GetShapeTypeColor());
		parent->StopDragging(this);

		if(m_controller)
		{
			GetScreen()->CloseSubMenu(this);
		}

		m_dragging = false;
		if(!effectAssigned)
		{
			OnRequireSkillEffect();
		}

		OnPlaceDone(true);
		return true;
	}
	else if(!m_controller)
	{
		// Using mouse
		parent->CancelSkill(this);
		parent->StopDragging(this);
		OnPlaceDone(false);
		return false;
	}
	else
	{
		OnPlaceDone(false);
		return false;
	}
}

void USkillWidget::StopDragging()
{
	if(m_dragging)
	{
		FVector2D mousePos;
		UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);
		FVector2D newPos = mousePos + m_offset;
		FVector4 gridresult = GetGridPos(newPos);
		FVector2D gridPos = FVector2D(gridresult.X, gridresult.Y);
		FVector2D gridIndex = FVector2D(gridresult.Z, gridresult.W);
		m_dragging = false;
		PlaceSkill();
	}
}

FVector2D USkillWidget::GetPositionFromIndex(FIntPoint in)
{
	FVector2D result;
	UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
	float viewportScale = UWidgetLayoutLibrary::GetViewportScale(parent);
	FVector2D topLeft = GetSkillTreePos();
	float scale = 32.0f * ( RenderTransform.Scale.X / 2);
	float XScale = (scale * 1.73205f);
	float YScale = scale;
	//FVector2D magicOffset = FVector2D(1.5, 4) * RenderTransform.Scale.X;
	float XIndex = (float)in.X;// -magicOffset.X;
	float YIndex = (float)in.Y;// -magicOffset.Y;
	result.X = XIndex * XScale + topLeft.X;
	result.Y = YIndex * YScale + topLeft.Y;
	return result;
}

FVector2D USkillWidget::GetSkillTreePos()
{
	UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
	float viewportScale = UWidgetLayoutLibrary::GetViewportScale(parent->GetCanvas());
	FVector2D topLeft;
	if (tmpSlot)
	{
		FVector2D screenTopRight = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY().X * tmpSlot->GetAnchors().Minimum.X, GEngine->GameViewport->Viewport->GetSizeXY().Y * tmpSlot->GetAnchors().Minimum.Y);
		FVector2D offset = tmpSlot->GetPosition() * viewportScale;
		FVector2D widgetTopLeft = ((tmpSlot->GetSize() * RenderTransform.Scale.X * viewportScale) / 2) ;
		topLeft = screenTopRight + offset - widgetTopLeft;
		topLeft /= viewportScale;
		//topLeft.X -= 16.0f;
	}
	return topLeft;
}

FVector2D USkillWidget::GetViewportPos()
{
	FVector2D result;
	FVector2D position;
	UCanvasPanelSlot* tmpSlot = Cast<UCanvasPanelSlot>( Slot );
	if ( tmpSlot )
	{
		position = tmpSlot->GetPosition( );
	}
	result.X = position.X;
	result.Y = position.Y;
	return result;
}

FVector4 USkillWidget::GetGridPos( FVector2D in )
{
	FVector2D result;
	FVector2D topLeft = GetSkillTreePos();
	float scale = 32.0f * (RenderTransform.Scale.X / 2);
	float XScale = (scale * 1.73205f);
	float YScale = scale;
	int32 XIndex = FMath::FloorToInt( ( in.X - topLeft.X ) / XScale );
	int32 YIndex = FMath::FloorToInt( ( in.Y - topLeft.Y ) / YScale );
	if ( XIndex % 2 == 0 )
		YIndex = roundToNearestOdd( YIndex );
	else
		YIndex = roundToNearestEven(YIndex);
	result.X = XIndex * XScale;
	result.X += topLeft.X;
	result.Y = YIndex * YScale;
	result.Y += topLeft.Y;
	m_lastGridIndex = FVector2D(XIndex, YIndex) - FVector2D(1, 0);// Store last grid position
	return FVector4(result.X , result.Y , XIndex, YIndex);
}

bool USkillWidget::CheckPosition(FVector2D in, TArray<FIntPoint>* points)
{
	bool result = true;
	TArray<FIntPoint> localPoints;
	//Check if positions are valid and available.
	for ( int32 x1 = 0; x1 < skillAsset->hexMap.width; x1++ )
	{
		for ( int32 y1 = 0; y1 < skillAsset->hexMap.height; y1++ )
		{
			if ( skillAsset->hexMap.Get( x1, y1 ) )
			{
				int32 x2 = FMath::FloorToInt( in.X );
				int32 y2;
				int32 angle = FMath::FloorToInt( m_canvasPanel->RenderTransform.Angle );
				FIntPoint pos1 = RotateHexPos( FIntPoint( x1 - skillAsset->pivot.X, y1 - skillAsset->pivot.Y ), angle, !(skillAsset->pivot.X & 1) );
				pos1.X += skillAsset->pivot.X;
				pos1.Y += skillAsset->pivot.Y;
				if ( FMath::FloorToInt( in.X ) % 2 != 0 && pos1.X % 2 != 0 )
					y2 = FMath::FloorToInt( ( in.Y + 1 ) / 2 );
				else
					y2 = FMath::FloorToInt( in.Y / 2 );
				FIntPoint pos2 = pos1 + FIntPoint( x2, y2 );
				localPoints.Push( pos2 );

				if (pos2.X < 0 || pos2.X >= 13 || pos2.Y < 0 || pos2.Y >= ( (pos2.X & 1) ? 15 : 16 ) || parent->skillTreeAsset->hexMap.Get(pos2.X, pos2.Y) || parent->placedSkillHexMap->Get(pos2.X, pos2.Y))
				{
					result = false;
					if ( !points )
					{
						break;
					}
				}
			}
		}
		if ( !result && !points ) break;
	}
	if ( points ) ( *points ) = localPoints;

	/*
	for ( int32 i = 0; i < parent->tiles.Num(); i++ )
	{
		bool test = true;
		for ( int32 j = 0; j < points.Num(); j++ )
		{
			if ( parent->tiles[i]->x == points[j].X && parent->tiles[i]->y == points[j].Y )
			{
				parent->tiles[i]->SetColorAndOpacity( FLinearColor::Yellow );
				parent->tiles[i]->SetVisibility( ESlateVisibility::Visible );
				test = false;
				break;
			}
		}
		if ( test )
		{
			if ( !parent->skillTreeAsset->hexMap.Get( parent->tiles[i]->x, parent->tiles[i]->y ) )
			{ 
				parent->tiles[i]->SetColorAndOpacity( FLinearColor::White );
				parent->tiles[i]->SetVisibility( ESlateVisibility::Visible );
			}
			else
			{
				parent->tiles[i]->SetColorAndOpacity( FLinearColor::White );
				parent->tiles[i]->SetVisibility( ESlateVisibility::Hidden );
			}
		}
	}
	*/
	return result;
}

void USkillWidget::SetSkillRotation(float angle)
{
	if(m_canvasPanel) m_canvasPanel->SetRenderAngle(angle);
	else YWARNING("No canvas panel found!");
	NativeOnSkillMove();
	OnRotate();
}

void USkillWidget::MoveSkill(FVector2D offset)
{
	//Check if odd
	FVector2D tmpOffset = offset;
	if (((int32)m_lastGridIndex.X) & 1 && tmpOffset.X != 0) tmpOffset.Y -= 1;
	if (!(((int32)m_lastGridIndex.X) & 1) && tmpOffset.X != 0) tmpOffset.Y += 1;
	m_lastGridIndex += tmpOffset;

	if(parent->lastGridIndex != m_lastGridIndex)
	{
		parent->lastGridIndex = m_lastGridIndex; // Store last index
		NativeOnSkillMove();
	}
}

void USkillWidget::MoveSkillAbsolute(FVector2D gridIndex)
{
	m_lastGridIndex = gridIndex; 
	parent->lastGridIndex = m_lastGridIndex; // Store last index
	NativeOnSkillMove();
}

void USkillWidget::ChangeColor(FLinearColor color)
{
	for ( int32 i = 0; i < m_hexagons.Num(); i++ )
	{
		if (m_hexagons[i]->material) m_hexagons[i]->material->SetVectorParameterValue("Skill_Color", color);
	}
}

void USkillWidget::UpdateLevel( float level )
{
	if (!m_dragable) return;
	for (int32 i = 0; i < m_hexagons.Num(); i++)
	{
		if( m_hexagons[i]->material ) m_hexagons[i]->material->SetScalarParameterValue("Skill_Level", level);
	}

	float offset = 1.0f - level;
	float skillHeight = 13.0f * offset;
	float height = FMath::CeilToFloat(skillHeight);
	int32 hexcount = 0;

	for (int32 i = 0; i < placedPoints.Num(); i++)
	{
		float YPos = ( placedPoints[i].X & 1 ) ? (float(placedPoints[i].Y) + 0.5f) : (float(placedPoints[i].Y));
		if ( YPos < height ) hexcount++;
	}

	m_power = float(placedPoints.Num()) / float(hexcount);
}

void USkillWidget::UpdateInfo(float skilltreeHeight, float skilltreeOffset)
{
	for (int32 i = 0; i < m_hexagons.Num(); i++)
	{
		if (m_hexagons[i]->material)
		{
			m_hexagons[i]->material->SetScalarParameterValue("Skill_Tree_Height", skilltreeHeight);
			m_hexagons[i]->material->SetScalarParameterValue("Skill_Offset", skilltreeOffset);
		}
	}
}

TArray<USkillWidget*> USkillWidget::ConnectedSkills(TArray<FIntPoint>& points)
{
	//Check if surrounding positions contain another skill.
	//if ( !PointsCointainsRoot(localPoints))
	//{
	TArray<USkillWidget*> result;
	const FIntPoint offsets[2][6]{
		{ FIntPoint(0, -1), FIntPoint(1, -1), FIntPoint(1, 0), FIntPoint(0, 1), FIntPoint(-1, 0), FIntPoint(-1, -1) },
		{ FIntPoint(0, -1), FIntPoint(1, 0), FIntPoint(1, 1), FIntPoint(0, 1), FIntPoint(-1, 1), FIntPoint(-1, 0) } };
	for (int32 i = 0; i < points.Num(); i++)
	{
		int32 k = points[i].X & 1;
		for (int32 j = 0; j < 6; j++)
		{
			FIntPoint checkPoint = points[i] + offsets[k][j];
			if ( points.Contains( checkPoint ) ) continue;
			if (parent->skillTreeAsset->hexMap.Get(checkPoint.X, checkPoint.Y)) continue;
			if (parent->placedSkillHexMap->Get(checkPoint.X, checkPoint.Y))
			{
				USkillWidget* widget = *parent->tileMap.Find(checkPoint);
				if (result.Contains(widget)) continue;
				result.Push(widget);
			}
		}
	}
	return result;
	//}
}

bool USkillWidget::ContainsRoot(TArray<FIntPoint>& points)
{
	return PointsCointainsRoot(points);
}

TArray<FIntPoint> USkillWidget::GetPoints()
{
	TArray<FIntPoint> points;
	CheckPosition(m_lastGridIndex, &points);
	return points;
}

bool USkillWidget::PointsCointainsRoot( TArray<FIntPoint>& points )
{
	for ( int32 i = 0; i < points.Num(); i++ )
	{
		if ( points[i] == parent->rootPoint ) return true;
	}
	return false;
}

void USkillWidget::NativeOnSkillMove()
{
	UpdateSkillColor();

	OnMove();
}

void USkillWidget::NativeTick( const FGeometry& geometry, float deltaTime )
{
	FVector2D mousePos;
	UWidgetLayoutLibrary::GetMousePositionScaledByDPI(GetOwningPlayer(), mousePos.X, mousePos.Y);

	if ( m_dragging && !m_controller )
	{
		FVector2D newPos = mousePos + m_offset;

		UCanvasPanelSlot* tmpSlot = Cast<UCanvasPanelSlot>( Slot );
		if ( tmpSlot )
		{
			FVector4 gridresult = GetGridPos( newPos );
			FVector2D gridPos = FVector2D( gridresult.X, gridresult.Y );
			FVector2D gridIndex = FVector2D( gridresult.Z, gridresult.W );
			if(gridPos != m_lastGridPos)
			{
				NativeOnSkillMove();
				m_lastGridPos = gridPos;
			}
		}
		else
			YWARNING( "Couldn't get Slot." );
	}
	else if( !m_dragging )
	{
		if (hovered)
		{
			ChangeColor(GetShapeTypeColor() * 2.0f);
		}
		else
		{
			ChangeColor(GetShapeTypeColor() * 0.5f);
		}
		if(parent->draggingWidget == this)
			parent->StopDragging(this);
	}
	if ( m_selected && m_enabled)
	{
		FVector2D mousePos;
		UWidgetLayoutLibrary::GetMousePositionScaledByDPI( GetOwningPlayer(), mousePos.X, mousePos.Y );
		FVector2D distanceVect = mousePos - m_mousedownPos;
		if ( distanceVect.SizeSquared() > 100 )
		{
			parent->NewSkill( this );
			m_selected = false;
		}
	}

	UCanvasPanelSlot* tmpSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(parent->GetCanvas());
	if (m_dragable)
	{
		float scale = 32.0f  * (RenderTransform.Scale.X / 2);
		float XScale = (scale * 1.73205f);
		float YScale = scale;

		FVector2D topLeft = GetSkillTreePos();
		FVector2D result;
		result.X = (m_lastGridIndex.X) * XScale;
		result.X += topLeft.X;
		result.Y = (m_lastGridIndex.Y) * YScale;
		result.Y += topLeft.Y;

		UCanvasPanelSlot* selfSlot = UWidgetLayoutLibrary::SlotAsCanvasSlot(this);
		if (selfSlot)
		{
			selfSlot->SetPosition(result);
		}
	}

	Super::NativeTick( geometry, deltaTime );
}

FLinearColor USkillWidget::GetShapeTypeColor() const
{
	if(selectedEffect == -1)
		return FLinearColor(1.0f, 1.0f, 1.0f) * 1.0f; // Hwhite

	static FLinearColor shapeTypeColors[] =
	{
		FLinearColor(0.1f, 1.0f, 0.3f) * 0.75f, // Green
		FLinearColor(1.0f, 0.3f, 0.1f) * 0.6f, // Red-Ish
		FLinearColor(0.0f, 0.0f, 1.0f) * 0.6f, // Blue
	};

	int32 idx = 0;
	if(skillAsset)
	{
		idx = (int32)skillAsset->abilityEffects[selectedEffect]->abilityCategory;
	}
	idx = FMath::Clamp(idx, 0, 2);
	return FLinearColor(shapeTypeColors[idx].R, shapeTypeColors[idx].G, shapeTypeColors[idx].B, 1.0f);
}

void USkillWidget::SetDragable(bool dragable, bool controller /*= false */)
{
	m_controller = controller;
	m_dragable = dragable;
	UpdateSkill();
}
