package net.qbar.common.grid;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Nonnull;

import net.qbar.common.steam.ISteamHandler;
import net.qbar.common.steam.SteamTank;

public class SteamGrid extends CableGrid
{
    private int                    transferCapacity;
    private final SteamTank        tank;

    private final List<ISteamPipe> connectedPipes;

    public SteamGrid(final int identifier, final int transferCapacity)
    {
        super(identifier);
        this.transferCapacity = transferCapacity;

        this.connectedPipes = new ArrayList<>();

        this.tank = new SteamTank(0, 0, 1.5f);
    }

    // TODO : Use pressure regulation instead of average pressure !
    @Override
    void tick()
    {
        super.tick();

        final Set<ISteamHandler> handlers = this.connectedPipes.stream()
                .flatMap(pipe -> pipe.getConnectedHandlers().stream()).collect(Collectors.toSet());
        handlers.add(this.tank);

        final double average = handlers.stream()
                .mapToDouble(handler -> handler.getPressure() / handler.getMaxPressure()).average().orElse(0);

        final ISteamHandler[] superiors = handlers.stream()
                .filter(handler -> handler.getPressure() / handler.getMaxPressure() - average > 0)
                .toArray(ISteamHandler[]::new);

        final ISteamHandler[] inferiors = handlers.stream()
                .filter(handler -> handler.getPressure() / handler.getMaxPressure() - average < 0)
                .toArray(ISteamHandler[]::new);

        final int drained = Stream.of(superiors).mapToInt(handler ->
        {
            return handler.drainSteam(Math.min(
                    (int) ((handler.getPressure() / handler.getMaxPressure() - average) * handler.getCapacity()),
                    this.transferCapacity), false);
        }).sum();
        int filled = 0;

        for (final ISteamHandler handler : inferiors)
        {
            filled += handler.fillSteam(Math.max(drained / inferiors.length, Math.min(
                    (int) ((handler.getPressure() / handler.getMaxPressure() - average) * handler.getCapacity()),
                    this.transferCapacity)), true);
        }

        for (final ISteamHandler handler : superiors)
        {
            handler.drainSteam(Math.max(filled / superiors.length, Math.min(
                    (int) ((handler.getPressure() / handler.getMaxPressure() - average) * handler.getCapacity()),
                    this.transferCapacity)), true);
        }
    }

    public SteamTank getTank()
    {
        return this.tank;
    }

    public boolean isEmpty()
    {
        return this.tank.getSteam() == 0;
    }

    public int getCapacity()
    {
        return this.getCables().size() * this.getTransferCapacity();
    }

    public int getTransferCapacity()
    {
        return this.transferCapacity;
    }

    public void setTransferCapacity(final int transferCapacity)
    {
        this.transferCapacity = transferCapacity;
    }

    public void addConnectedPipe(final ISteamPipe pipe)
    {
        this.connectedPipes.add(pipe);
    }

    public void removeConnectedPipe(final ISteamPipe pipe)
    {
        this.connectedPipes.remove(pipe);
    }

    @Override
    public void addCable(@Nonnull final ITileCable cable)
    {
        super.addCable(cable);
        this.getTank().setCapacity(this.getCapacity());
    }

    @Override
    public boolean removeCable(final ITileCable cable)
    {
        if (super.removeCable(cable))
        {
            this.getTank().setCapacity(this.getCapacity());
            return true;
        }
        return false;
    }
}

@@ -738,76 +738,8 @@
  %7D%0A%0A
-    // TODO : Use pressure regulation instead of average pressure !%0A
     
@@ -1048,33 +1048,16 @@
 stream()
-%0A                
 .mapToDo
@@ -1097,35 +1097,8 @@
 re()
- / handler.getMaxPressure()
 ).av
@@ -1147,25 +1147,21 @@
 ndler%5B%5D 
-superiors
+above
  = handl
@@ -1172,33 +1172,16 @@
 stream()
-%0A                
 .filter(
@@ -1216,35 +1216,8 @@
 re()
- / handler.getMaxPressure()
  - a
@@ -1268,33 +1268,32 @@
 andler%5B%5D::new);%0A
-%0A
         final IS
@@ -1306,25 +1306,21 @@
 ndler%5B%5D 
-inferiors
+below
  = handl
@@ -1331,33 +1331,16 @@
 stream()
-%0A                
 .filter(
@@ -1375,35 +1375,8 @@
 re()
- / handler.getMaxPressure()
  - a
@@ -1474,25 +1474,21 @@
 ream.of(
-superiors
+above
 ).mapToI
@@ -1549,25 +1549,16 @@
 inSteam(
-Math.min(
 %0A       
@@ -1574,40 +1574,25 @@
     
-(int) ((handler.getPressure() / 
+Math.min((int) ((
 hand
@@ -1590,35 +1590,32 @@
 t) ((handler.get
-Max
 Pressure() - ave
@@ -1645,36 +1645,16 @@
 city()),
-%0A                   
  this.tr
@@ -1669,16 +1669,36 @@
 pacity),
+%0A                   
  false);
@@ -1788,28 +1788,14 @@
 r : 
-inferiors)%0A        %7B
+below)
 %0A   
@@ -1827,24 +1827,45 @@
 r.fillSteam(
+%0A                    
 Math.max(dra
@@ -1875,17 +1875,13 @@
 d / 
-inferiors
+below
 .len
@@ -1887,32 +1887,40 @@
 ngth, Math.min(%0A
+        
                 
@@ -1956,35 +1956,8 @@
 re()
- / handler.getMaxPressure()
  - a
@@ -1989,36 +1989,16 @@
 city()),
-%0A                   
  this.tr
@@ -2006,39 +2006,32 @@
 nsferCapacity)),
- true);
 %0A        %7D%0A%0A    
@@ -2019,25 +2019,42 @@
 )),%0A        
-%7D
+            true);
 %0A%0A        fo
@@ -2090,28 +2090,14 @@
 r : 
-superiors)%0A        %7B
+above)
 %0A   
@@ -2124,16 +2124,37 @@
 inSteam(
+%0A                    
 Math.max
@@ -2167,17 +2167,13 @@
 d / 
-superiors
+above
 .len
@@ -2199,32 +2199,40 @@
                 
+        
 (int) ((handler.
@@ -2248,35 +2248,8 @@
 re()
- / handler.getMaxPressure()
  - a
@@ -2281,36 +2281,16 @@
 city()),
-%0A                   
  this.tr
@@ -2306,23 +2306,16 @@
 acity)),
- true);
 %0A       
@@ -2311,25 +2311,42 @@
 )),%0A        
-%7D
+            true);
 %0A    %7D%0A%0A    

Fix pressure repartition