/***************************************************************************************************
efx_NSContrast.cpp

Copyright © John Paul Chacha. All Rights Reserved.

This source code file, which has been provided by John Paul Chacha as part of his software product 
for use only by licensed users of that product, includes proprietary information of John Paul Chacha

USE OF THIS SOFTWARE IS GOVERNED BY THE TERMS AND CONDITIONS OF THE LICENSE AGREEMENT FURNISHED WITH
THE PRODUCT

IN PARTICULAR, JOHN PAUL CHACHA SHALL BE FREE FROM ANY CLAIMS OR LIABILITIES ARISING OUT OF THE USE
OR MISUSE OF THIS FILE AND/OR ITS CONTENTS
***************************************************************************************************/
#include "../common/system.h"
#include "../common/suite_defs.h"
#include "../common/plugin.h"
#include "../common/win_util.h"
#include "../common/str_util.h"
#include "resource.h"


//==================================================================================================
#define PLUGIN_NAME			L"Non-saturating Contrast Effect"
#define PLUGIN_AUTHOR		SUITE_CREATOR
#define PLUGIN_VERSION		SUITE_VER_UINT32
#define MY_STORE_NAME		L"efx_NSContrast.dll"
#define MY_STORE_UUID		(*((unsigned long*)("xNSC")))

#define APP_MSG_NOTIFY		WM_APP+1

//--------------------------------------------------------------------------------------------------
struct my_plg_status
{
	unsigned long	uuid;
	int				power;
};

//--------------------------------------------------------------------------------------------------
HINSTANCE			api_inst;
efx_IMAGE_T*		p_host=0;
my_plg_status		tmp_settings={0,};

//--------------------------------------------------------------------------------------------------
INT_PTR CALLBACK msg_dlg_about (HWND hDlg,UINT msg,WPARAM wpar,LPARAM lpar);
INT_PTR CALLBACK msg_dlg_effect(HWND hDlg,UINT msg,WPARAM wpar,LPARAM lpar);

//==================================================================================================
//==================================================================================================


/***************************************************************************************************
This function is called during DLL startup/shutdown.
***************************************************************************************************/
BOOL APIENTRY DllMain(HANDLE hModule,unsigned long ul_reason_for_call,LPVOID lpReserved)
{
	switch(ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		api_inst=(HINSTANCE)hModule;
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		break;
	}
	UNREFERENCED_PARAMETER(lpReserved);
	return TRUE;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////


/***************************************************************************************************
This function is called to query plugin's name and type.
***************************************************************************************************/
int plg_GetInfo(plg_INFO* info)
{
	info->api_type=PLUGIN_APITYPE_EFFECT;
	info->api_version=PLUGIN_INTERFACE_VERSION;
	info->plg_version=PLUGIN_VERSION;
	StringCchCopy(info->plg_name  ,_countof(info->plg_name)  ,PLUGIN_NAME  );
	StringCchCopy(info->plg_author,_countof(info->plg_author),PLUGIN_AUTHOR);
	return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////


/***************************************************************************************************
This function is called to display plugin dialog boxes
***************************************************************************************************/
int plg_ShowDialog(plg_DIALOG* host)
{
	int bit_len=host->param_1;
	double scale;

	scale=(double)(1i64<<(bit_len-32));
	if(!host)
	{
		return PLUGIN_ERR_BAD_PARAM;
	}
	switch(host->dialog_id)
	{
	case PLUGIN_DIALOG_ID_ABOUT:
		DialogBoxParam(api_inst,(LPCTSTR)IDD_ABOUT,host->hwnd,msg_dlg_about,0);
		return 1;
	case PLUGIN_DIALOG_ID_CONFIG:
		return PLUGIN_ERR_NO_SUPPORT;
	case PLUGIN_DIALOG_ID_HELP:
		return PLUGIN_ERR_NO_SUPPORT;
	}
	return PLUGIN_ERR_BAD_PARAM;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////


/***************************************************************************************************
This is the plugin DLL function that Chasys Photo calls to run the effect exposed by this plugin
***************************************************************************************************/
int efx_DoEffect(efx_IMAGE_T* host)
{
	int i,ret;

	//----------------------------------------------------------------------------------------------
	if(!host)
	{
		return PLUGIN_ERR_BAD_PARAM;
	}
	if(!host->pi_BasicImage)
	{
		return PLUGIN_ERR_BAD_HOST;
	}
	if(!(PLUGIN_TEST_PI_VERSION(host->pi_BasicImage->version,PI_BASICIMAGE_VERSION)))
	{
		return PLUGIN_ERR_BAD_HOST;
	}

	//----------------------------------------------------------------------------------------------
	p_host=host;

	//----------------------------------------------------------------------------------------------
	tmp_settings.power=100;
	if(host->pi_StateStore)
	{
		i=host->pi_StateStore->temporary_size(MY_STORE_NAME);
		if(i>=sizeof(tmp_settings))
		{
			host->pi_StateStore->temporary_read(MY_STORE_NAME,&tmp_settings,sizeof(tmp_settings));
		}
	}

	//----------------------------------------------------------------------------------------------
	host->load(host);
	ret=DialogBoxParam(api_inst,(LPCTSTR)IDD_EFFECT,host->hwnd,msg_dlg_effect,0);
	if(ret==0)
	{
		return PLUGIN_ERR_USER_CANCEL;
	}
	if(ret<0)
	{
		return PLUGIN_ERR_INTERNAL_U;
	}

	//----------------------------------------------------------------------------------------------
	if(host->pi_StateStore)
	{
		host->pi_StateStore->temporary_write(MY_STORE_NAME,&tmp_settings,sizeof(tmp_settings));
	}
	return PLUGIN_OKAY;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////


/***************************************************************************************************
***************************************************************************************************/
int effect_Execute(int power)
{
	int i;
	unsigned char xlat[256];
	pibi_IMAGE b_img={0,};

	//----------------------------------------------------------------------------------------------
	//reload original every time we update
	if(!p_host)
	{
		return 0;
	}
	if(!(p_host->load(p_host)))
	{
		return 0;
	}

	//----------------------------------------------------------------------------------------------
	//calc xlat tables
	for(i=0;i<=127;i++)
	{
		xlat[i]=(unsigned char)(127.0*pow((i/127.0),1.0+(power/100.0)));
	}
	for(i=128;i<256;i++)
	{
		xlat[i]=(unsigned char)(255-xlat[255-i]);
	}

	//----------------------------------------------------------------------------------------------
	//lock host, virtualize, execute xlat, then unlock
	if(p_host->lock(p_host))
	{
		p_host->pi_BasicImage->virtualize(&b_img,p_host->width,p_host->height,p_host->pitch,
			p_host->lp_pix);
		p_host->pi_BasicImage->translate(&b_img,0,0,b_img.width-1,b_img.height-1,xlat,xlat,xlat,
			0,0,0);
		p_host->pi_BasicImage->destroy(&b_img);
		p_host->unlock(p_host);
	}

	//----------------------------------------------------------------------------------------------
	//force host to refresh its display to reflect changes
	p_host->refresh(p_host);
	return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////


/***************************************************************************************************
***************************************************************************************************/
INT_PTR CALLBACK msg_dlg_effect(HWND hDlg,UINT msg,WPARAM wpar,LPARAM lpar)
{
	SCROLLINFO si;

	//----------------------------------------------------------------------------------------------
	switch(msg)
	{
	//----------------------------------------------------------------------------------------------
	case WM_INITDIALOG:
		SetWindowText(hDlg,PLUGIN_NAME);
		memset(&si,0,sizeof(si));
		si.cbSize=sizeof(si);
		si.fMask=SIF_PAGE|SIF_POS|SIF_RANGE;
		si.nPage=100;
		si.nMin=0;
		si.nMax=1000;
		si.nPos=tmp_settings.power;
		SetScrollInfo(GetDlgItem(hDlg,IDC_SCROLL1),SB_CTL,&si,TRUE);
		p_host->dock(p_host,hDlg);

		effect_Execute(tmp_settings.power);
		return 1|lpar;

	//----------------------------------------------------------------------------------------------
	case WM_HSCROLL:
		memset(&si,0,sizeof(si));
		si.cbSize=sizeof(si);
		si.fMask=SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
		GetScrollInfo(GetDlgItem(hDlg,IDC_SCROLL1),SB_CTL,&si);
		si.nPage=100;
		si.nMin=0;
		si.nMax=1000;
		switch(LOWORD(wpar))
		{
		case SB_LEFT:
			si.nPos=si.nMin;
            break;
		case SB_RIGHT:
			si.nPos=si.nMax;
			break;
		case SB_LINELEFT:
			si.nPos-=1;
			break;
		case SB_LINERIGHT:
			si.nPos+=1;
            break;
		case SB_PAGELEFT:
			si.nPos-=100;
            break;
		case SB_PAGERIGHT:
			si.nPos+=100;
			break;
		case SB_THUMBTRACK:
			si.nPos=si.nTrackPos;
			break;
		case SB_ENDSCROLL:
			break;
		}
		si.nPos=max(si.nPos,si.nMin);
		si.fMask=SIF_PAGE|SIF_POS|SIF_RANGE;
		SetScrollInfo(GetDlgItem(hDlg,IDC_SCROLL1),SB_CTL,&si,TRUE);
		GetScrollInfo(GetDlgItem(hDlg,IDC_SCROLL1),SB_CTL,&si);
		tmp_settings.power=si.nPos;

		effect_Execute(tmp_settings.power);
		break;

	//----------------------------------------------------------------------------------------------
	case WM_COMMAND:
		switch(LOWORD(wpar))
		{
		case IDOK:
			effect_Execute(tmp_settings.power);
			EndDialog(hDlg,1);
			break;
		case IDCANCEL:
			EndDialog(hDlg,0);
			break;
		}
		break;

	//----------------------------------------------------------------------------------------------
	case WM_SHOWWINDOW:
		SetWindowPos(hDlg,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOSENDCHANGING);
		break;
	}
	//----------------------------------------------------------------------------------------------
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////


/***************************************************************************************************
This function processes messages for the about dialog
***************************************************************************************************/
INT_PTR CALLBACK msg_dlg_about(HWND hDlg,UINT msg,WPARAM wpar,LPARAM lpar)
{
	wchar_t* pstr;

	//----------------------------------------------------------------------------------------------
	switch(msg)
	{
	case WM_INITDIALOG:
		SetWindowText(hDlg,L"About " PLUGIN_NAME);
		//lang_TranslateWindow(hDlg);
		pstr=string_ReadTextResource(api_inst,(LPCTSTR)IDR_README,L"TEXT");
		if(pstr)
		{
			string_SetNewline(pstr,GlobalSize(pstr)/sizeof(wchar_t),true);
			SetDlgItemText(hDlg,IDC_EDIT1,pstr);
			GlobalFree(pstr);
		}
		window_Center(hDlg,GetParent(hDlg));
		return 1|lpar;
	case WM_COMMAND:
		switch(LOWORD(wpar))
		{
		case IDOK:
			EndDialog(hDlg,1);
			break;
		case IDCANCEL:
			EndDialog(hDlg,0);
			break;
		}
		break;
	}
	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
