/*
 ** a_lighttransfer.cpp
 **
 **---------------------------------------------------------------------------
 ** Copyright 1998-2016 Randy Heit
 ** Copyright 2003-2018 Christoph Oelckers
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions
 ** are met:
 **
 ** 1. Redistributions of source code must retain the above copyright
 **    notice, this list of conditions and the following disclaimer.
 ** 2. Redistributions in binary form must reproduce the above copyright
 **    notice, this list of conditions and the following disclaimer in the
 **    documentation and/or other materials provided with the distribution.
 ** 3. The name of the author may not be used to endorse or promote products
 **    derived from this software without specific prior written permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **---------------------------------------------------------------------------
 **
 */

#include "p_spec.h"
#include "a_lighttransfer.h"
#include "serializer.h"
#include "g_levellocals.h"

//
// SPECIAL SPAWNING
//

IMPLEMENT_CLASS(DLightTransfer, false, false)

void DLightTransfer::Serialize(FSerializer &arc)
{
	Super::Serialize (arc);
	arc("lastlight", LastLight)
		("source", Source)
		("targettag", TargetTag)
		("copyfloor", CopyFloor);
}

void DLightTransfer::Construct(sector_t *srcSec, int target, bool copyFloor)
{
	int secnum;

	Source = srcSec;
	TargetTag = target;
	CopyFloor = copyFloor;
	DoTransfer (LastLight = srcSec->lightlevel, target, copyFloor);

	if (copyFloor)
	{
		auto itr = Level->GetSectorTagIterator(target);
		while ((secnum = itr.Next()) >= 0)
			Level->sectors[secnum].ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
	}
	else
	{
		auto itr = Level->GetSectorTagIterator(target);
		while ((secnum = itr.Next()) >= 0)
			Level->sectors[secnum].ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
	}
}

void DLightTransfer::Tick ()
{
	int light = Source->lightlevel;

	if (light != LastLight)
	{
		LastLight = light;
		DoTransfer (light, TargetTag, CopyFloor);
	}
}

void DLightTransfer::DoTransfer (int llevel, int target, bool floor)
{
	int secnum;

	if (floor)
	{
		auto itr = Level->GetSectorTagIterator(target);
		while ((secnum = itr.Next()) >= 0)
			Level->sectors[secnum].SetPlaneLight(sector_t::floor, llevel);
	}
	else
	{
		auto itr = Level->GetSectorTagIterator(target);
		while ((secnum = itr.Next()) >= 0)
			Level->sectors[secnum].SetPlaneLight(sector_t::ceiling, llevel);
	}
}


IMPLEMENT_CLASS(DWallLightTransfer, false, false)

void DWallLightTransfer::Serialize(FSerializer &arc)
{
	Super::Serialize (arc);
	arc("lastlight", LastLight)
		("source", Source)
		("targetid", TargetID)
		("flags", Flags);
}

void DWallLightTransfer::Construct(sector_t *srcSec, int target, uint8_t flags)
{
	int linenum;
	int wallflags;

	Source = srcSec;
	TargetID = target;
	Flags = flags;
	DoTransfer (LastLight = srcSec->GetLightLevel(), target, Flags);

	if (!(flags & WLF_NOFAKECONTRAST))
	{
		wallflags = WALLF_ABSLIGHTING;
	}
	else
	{
		wallflags = WALLF_ABSLIGHTING | WALLF_NOFAKECONTRAST;
	}

	auto itr = Level->GetLineIdIterator(target);
	while ((linenum = itr.Next()) >= 0)
	{
		if (flags & WLF_SIDE1 && Level->lines[linenum].sidedef[0] != NULL)
		{
			Level->lines[linenum].sidedef[0]->Flags |= wallflags;
		}

		if (flags & WLF_SIDE2 && Level->lines[linenum].sidedef[1] != NULL)
		{
			Level->lines[linenum].sidedef[1]->Flags |= wallflags;
		}
	}
}

void DWallLightTransfer::Tick ()
{
	short light = sector_t::ClampLight(Source->lightlevel);

	if (light != LastLight)
	{
		LastLight = light;
		DoTransfer (light, TargetID, Flags);
	}
}

void DWallLightTransfer::DoTransfer (short lightlevel, int target, uint8_t flags)
{
	int linenum;

	auto itr = Level->GetLineIdIterator(target);
	while ((linenum = itr.Next()) >= 0)
	{
		line_t *line = &Level->lines[linenum];

		if (flags & WLF_SIDE1 && line->sidedef[0] != NULL)
		{
			line->sidedef[0]->SetLight(lightlevel);
		}

		if (flags & WLF_SIDE2 && line->sidedef[1] != NULL)
		{
			line->sidedef[1]->SetLight(lightlevel);
		}
	}
}

