#include "ButtonData.h"

#include "OpacityTokens.h"

const float ButtonData::DEFAULT_CONTAINER_OPACITY = 1;

const std::map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mContainerColors = {
	{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Surface},

	{{Component::Elevated, State::Disabled}, Theme::Sys::Color::On_Surface},
	{{Component::Elevated, State::Hovered}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Focused}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Pressed}, Theme::Sys::Color::Primary},

	{{Component::Filled, State::Enabled}, Theme::Sys::Color::Primary},
	{{Component::Filled, State::Disabled}, Theme::Sys::Color::On_Surface},
	{{Component::Filled, State::Hovered}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Focused}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Pressed}, Theme::Sys::Color::On_Primary},
};

const std::map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mContainerShadowColors = {
	{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Shadow},
	{{Component::Filled, State::Enabled}, Theme::Sys::Color::Shadow},
};

const std::map<ButtonData::ComponentState, Theme::Sys::Elevation> ButtonData::mContainerElevations = {
	{{Component::Elevated, State::Enabled}, Theme::Sys::Elevation::Level_1},
	{{Component::Elevated, State::Disabled}, Theme::Sys::Elevation::Level_0},
	{{Component::Elevated, State::Hovered}, Theme::Sys::Elevation::Level_2},
	{{Component::Elevated, State::Focused}, Theme::Sys::Elevation::Level_1},

	{{Component::Filled, State::Enabled}, Theme::Sys::Elevation::Level_0},
	{{Component::Filled, State::Disabled}, Theme::Sys::Elevation::Level_0},
	{{Component::Filled, State::Hovered}, Theme::Sys::Elevation::Level_1},
	{{Component::Filled, State::Focused}, Theme::Sys::Elevation::Level_0},
	{{Component::Filled, State::Pressed}, Theme::Sys::Elevation::Level_0},
};

const std::map<ButtonData::ComponentState, float> ButtonData::mContainerOpacity = {
	{{Component::Elevated, State::Disabled}, 0.12f},
	{{Component::Elevated, State::Hovered}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Hover)},
	{{Component::Elevated, State::Focused}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Focus)},
	{{Component::Elevated, State::Pressed}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Pressed)},

	{{Component::Filled, State::Disabled}, 0.12f},
	{{Component::Filled, State::Hovered}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Hover)},
	{{Component::Filled, State::Focused}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Focus)},
	{{Component::Filled, State::Pressed}, OpacityTokens::getValue(Theme::Sys::StateLayerOpacity::State::Pressed)},
};

const std::map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mLabelTextColors = {
	{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Disabled}, Theme::Sys::Color::On_Surface},
	{{Component::Elevated, State::Hovered}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Focused}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Pressed}, Theme::Sys::Color::Primary},

	{{Component::Filled, State::Enabled}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Disabled}, Theme::Sys::Color::On_Surface},
	{{Component::Filled, State::Hovered}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Focused}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Pressed}, Theme::Sys::Color::On_Primary},
};

const std::map<ButtonData::ComponentState, Theme::Sys::Typescale> ButtonData::mLabelTypescales = {
	{{Component::Elevated, State::Enabled}, Theme::Sys::Typescale::Label_Large},
	{{Component::Filled, State::Enabled}, Theme::Sys::Typescale::Label_Large},
};

const std::map<ButtonData::ComponentState, float> ButtonData::mLabelTextOpacity = {
	{{Component::Elevated, State::Disabled}, 0.38f},
	{{Component::Filled, State::Disabled}, 0.38f},
};

const std::map<ButtonData::ComponentState, Theme::Sys::Color> ButtonData::mIconColors = {
	{{Component::Elevated, State::Enabled}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Disabled}, Theme::Sys::Color::On_Surface},
	{{Component::Elevated, State::Hovered}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Focused}, Theme::Sys::Color::Primary},
	{{Component::Elevated, State::Pressed}, Theme::Sys::Color::Primary},

	{{Component::Filled, State::Enabled}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Disabled}, Theme::Sys::Color::On_Surface},
	{{Component::Filled, State::Hovered}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Focused}, Theme::Sys::Color::On_Primary},
	{{Component::Filled, State::Pressed}, Theme::Sys::Color::On_Primary},
};

const std::map<ButtonData::ComponentState, float> ButtonData::mIconOpacity = {
	{{Component::Elevated, State::Disabled}, 0.38f},
	{{Component::Filled, State::Disabled}, 0.38f},
};

Theme::Sys::Color ButtonData::getContainerColor() const
{
	if (auto iter = mContainerColors.find(std::make_pair(mComponent, mState)); iter != mContainerColors.end())
	{
		return iter->second;
	}
	else
	{
		if (mState == State::Enabled)
		{
			return DEFAULT_CONTAINER_COLOR;
		}
		else if (auto iter = mContainerColors.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerColors.end())
		{
			return iter->second;
		}
		else
		{
			return DEFAULT_CONTAINER_COLOR;
		}	
	}
}

Theme::Sys::Color ButtonData::getContainerShadowColor() const
{
	if (auto iter = mContainerShadowColors.find(std::make_pair(mComponent, mState)); iter != mContainerShadowColors.end())
	{
		return iter->second;
	}
	else
	{
		if (mState == State::Enabled)
		{
			return DEFAULT_CONTAINER_SHADOW_COLOR;
		}
		else if (auto iter = mContainerShadowColors.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerShadowColors.end())
		{
			return iter->second;
		}
		else
		{
			return DEFAULT_CONTAINER_SHADOW_COLOR;
		}
	}
}

Theme::Sys::Color ButtonData::getContainerSurfaceTintColor() const
{
	switch (mComponent)
	{
	case Component::Elevated:
		return Theme::Sys::Color::Surface_Tint_Color;
	default:
		return Theme::Sys::Color::None;
	}
}

Theme::Sys::Color ButtonData::getLabelTextColor() const
{
	if (auto iter = mLabelTextColors.find(std::make_pair(mComponent, mState)); iter != mLabelTextColors.end())
	{
		return iter->second;
	}
	else
	{
		if (mState == State::Enabled)
		{
			return getContainerColor();
		}
		else if (auto iter = mLabelTextColors.find(std::make_pair(mComponent, State::Enabled)); iter != mLabelTextColors.end())
		{
			return iter->second;
		}
		else
		{
			return getContainerColor();
		}
	}
}

Theme::Sys::Elevation ButtonData::getContainerElevation() const
{
	if (auto iter = mContainerElevations.find(std::make_pair(mComponent, mState)); iter != mContainerElevations.end())
	{
		return iter->second;
	}
	else
	{
		if (mState == State::Enabled)
		{
			return DEFAULT_CONTAINER_ELEVATION;
		}
		else if (auto iter = mContainerElevations.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerElevations.end())
		{
			return iter->second;
		}
		else
		{
			return DEFAULT_CONTAINER_ELEVATION;
		}
	}
}

float ButtonData::getStateLayerOverlayOpacity() const
{
	if (auto iter = mContainerOpacity.find(std::make_pair(mComponent, mState)); iter != mContainerOpacity.end())
	{
		return iter->second;
	}
	else
	{
		if (mState == State::Enabled)
		{
			return DEFAULT_CONTAINER_OPACITY;
		}
		else if (auto iter = mContainerOpacity.find(std::make_pair(mComponent, State::Enabled)); iter != mContainerOpacity.end())
		{
			return iter->second;
		}
		else
		{
			return DEFAULT_CONTAINER_OPACITY;
		}
	}
}

float ButtonData::getLabelOpacity() const
{
	if (auto iter = mLabelTextOpacity.find(std::make_pair(mComponent, mState)); iter != mLabelTextOpacity.end())
	{
		return iter->second;
	}
	else
	{
		if (mState == State::Enabled)
		{
			return DEFAULT_CONTAINER_OPACITY;
		}
		else if (auto iter = mLabelTextOpacity.find(std::make_pair(mComponent, State::Enabled)); iter != mLabelTextOpacity.end())
		{
			return iter->second;
		}
		else
		{
			return DEFAULT_CONTAINER_OPACITY;
		}
	}
}

Theme::Sys::Typescale ButtonData::getLabelTypescale() const
{
	switch (mComponent)
	{
	case Component::Elevated:
		return Theme::Sys::Typescale::Label_Large;
	default:
		return Theme::Sys::Typescale::Label_Large;
	}
}

bool ButtonData::canHaveIcon() const
{
	switch (mComponent)
	{
	case Component::Elevated:
		return true;
	default:
		return false;
	}
}

Theme::Sys::Color ButtonData::getIconColor() const
{
	switch (mComponent)
	{
	case Component::Elevated:
		return Theme::Sys::Color::Primary;
	default:
		return Theme::Sys::Color::None;
	}
}

unsigned ButtonData::getContainerHeight() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 40;
	default:
		return 40;
	}
}

unsigned ButtonData::getContainerCornerRadius() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 20;
	default:
		return 20;
	}
}

unsigned ButtonData::getIconSize() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 18;
	default:
		return 18;
	}
}

unsigned ButtonData::getLeftRightPadding() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 24;
	default:
		return 24;
	}
}

unsigned ButtonData::getLeftPaddingWithIcon() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 16;
	default:
		return 16;
	}
}

unsigned ButtonData::getRightPaddingWithIcon() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 24;
	default:
		return 24;
	}
}

unsigned ButtonData::getBetweenElementPadding() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return 8;
	default:
		return 8;
	}
}

ButtonData::LabelTextAlign ButtonData::getLabelTextAlign() const
{
	switch (mComponent)
	{
	case Component::Elevated:
	case Component::Filled:
		return ButtonData::LabelTextAlign::Centre;
	default:
		return ButtonData::LabelTextAlign::Centre;
	}
}