/*
* This file is part of Matter Overdrive
* Copyright (c) 2015., Simeon Radivoev, All rights reserved.
*
* Matter Overdrive is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Matter Overdrive is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Matter Overdrive. If not, see <http://www.gnu.org/licenses>.
*/
package matteroverdrive.machines.analyzer.components;
import cpw.mods.fml.common.gameevent.TickEvent;
import matteroverdrive.Reference;
import matteroverdrive.api.matter.IMatterDatabase;
import matteroverdrive.api.network.IMatterNetworkConnection;
import matteroverdrive.api.network.MatterNetworkTask;
import matteroverdrive.api.network.MatterNetworkTaskState;
import matteroverdrive.data.ItemPattern;
import matteroverdrive.machines.analyzer.TileEntityMachineMatterAnalyzer;
import matteroverdrive.matter_network.MatterNetworkPacket;
import matteroverdrive.matter_network.components.MatterNetworkComponentClientDispatcher;
import matteroverdrive.matter_network.packets.MatterNetworkRequestPacket;
import matteroverdrive.matter_network.packets.MatterNetworkResponsePacket;
import matteroverdrive.matter_network.tasks.MatterNetworkTaskStorePattern;
import matteroverdrive.util.MatterNetworkHelper;
import matteroverdrive.util.TimeTracker;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
/**
* Created by Simeon on 7/13/2015.
*/
public class MatterNetworkComponentAnalyzer extends MatterNetworkComponentClientDispatcher<MatterNetworkTaskStorePattern,TileEntityMachineMatterAnalyzer>
{
private IMatterNetworkConnection connection;
private boolean badLocation;
private TimeTracker broadcastTracker,validDestinationTracker;
public MatterNetworkComponentAnalyzer(TileEntityMachineMatterAnalyzer analyzer)
{
super(analyzer,TickEvent.Phase.START);
broadcastTracker = new TimeTracker();
validDestinationTracker = new TimeTracker();
handlers.add(BASIC_CONNECTIONS_HANDLER);
}
@Override
protected void executePacket(MatterNetworkPacket packet)
{
if (packet instanceof MatterNetworkResponsePacket)
{
executeResponses((MatterNetworkResponsePacket)packet);
}
}
protected void executeResponses(MatterNetworkResponsePacket packet)
{
if (packet.fits(Reference.PACKET_RESPONCE_INVALID,Reference.PACKET_REQUEST_VALID_PATTERN_DESTINATION))
{
badLocation = true;
connection = null;
}else if (packet.fits(Reference.PACKET_RESPONCE_VALID,Reference.PACKET_REQUEST_VALID_PATTERN_DESTINATION) && !badLocation)
{
if (isConnectionBetter(connection,packet)) {
connection = packet.getSender(rootClient.getWorldObj());
}
}
}
@Override
public int manageTopQueue(World world,int queueID, MatterNetworkTaskStorePattern task) {
int broadcastCount = 0;
if (task.getState() == MatterNetworkTaskState.FINISHED)
{
onTaskComplete(rootClient.getTaskQueue(0).dequeue());
}
else
{
if (canBroadcastTask(world, task)) {
for (int i = 0; i < 6; i++) {
if (MatterNetworkHelper.broadcastPacketInDirection(world, (byte) 0, task, rootClient, ForgeDirection.getOrientation(i), connection != null ? MatterNetworkHelper.getFilterFromPositions(connection.getPosition()) : null)) {
onTaskBroadcast(world, task, ForgeDirection.getOrientation(i));
broadcastCount++;
}
}
}
}
rootClient.getTaskQueue(queueID).tickAllAlive(world, false);
return broadcastCount;
}
@Override
public int onNetworkTick(World world, TickEvent.Phase phase)
{
int broadcasts = super.onNetworkTick(world,phase);
if (phase.equals(TickEvent.Phase.START))
{
broadcasts += manageValidDestinationCheck(world);
}
return broadcasts;
}
private boolean isConnectionBetter(IMatterNetworkConnection one,MatterNetworkResponsePacket two)
{
if (one == null && two != null)
return true;
if (one == null && two == null)
return false;
if (!(two.getSender(rootClient.getWorldObj()) instanceof IMatterDatabase))
return false;
ItemPattern packetPattern = new ItemPattern(two.getResponse());
ItemStack packetPatternStack = packetPattern.toItemStack(false);
if (packetPattern != null && packetPatternStack != null)
{
if (one instanceof IMatterDatabase) {
ItemPattern patternOne = ((IMatterDatabase) one).getPattern(packetPatternStack);
if (patternOne != null)
{
int oneProgress = patternOne.getProgress();
int twoProgress = packetPattern.getProgress();
if (oneProgress < twoProgress)
{
return true;
}
}
}else
{
return true;
}
}
return false;
}
private int manageValidDestinationCheck(World world)
{
int broadcastCount = 0;
if (rootClient.isActive() || (getTaskQueue(0).size() > 0 && connection == null))
{
if (validDestinationTracker.hasDelayPassed(world, TileEntityMachineMatterAnalyzer.VALID_LOCATION_CHECK_DELAY))
{
for (int i = 0; i < 6; i++) {
MatterNetworkRequestPacket packet = new MatterNetworkRequestPacket(rootClient, Reference.PACKET_REQUEST_VALID_PATTERN_DESTINATION,ForgeDirection.getOrientation(i),rootClient.getFilter(), new ItemPattern(rootClient.getInventory().getStackInSlot(rootClient.input_slot)));
if (MatterNetworkHelper.broadcastPacketInDirection(world, packet, rootClient, ForgeDirection.getOrientation(i)))
{
resetValidLocation();
broadcastCount++;
}
}
}
}
return broadcastCount;
}
public void resetValidLocation()
{
connection = null;
badLocation = false;
}
private boolean canBroadcastTask(World world,MatterNetworkTask task)
{
return !task.isAlive() &&
broadcastTracker.hasDelayPassed(world, task.getState() == MatterNetworkTaskState.WAITING ? TileEntityMachineMatterAnalyzer.BROADCAST_WEATING_DELAY : TileEntityMachineMatterAnalyzer.BROADCAST_DELAY);
}
//region Events
private void onTaskComplete(MatterNetworkTask task)
{
rootClient.forceSync();
}
private void onTaskBroadcast(World world,MatterNetworkTask task,ForgeDirection direction)
{
task.setState(MatterNetworkTaskState.WAITING);
}
//endregion
//region Getters and Setters
public IMatterNetworkConnection getConnection()
{
return connection;
}
//endregion
}