package com.jcumulus.server.rtmfp.publisher;

/**
 * jCumulus is a Java port of Cumulus OpenRTMP
 *
 * Copyright 2011 OpenRTMFP
 *
 * This program 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.
 *
 * This program 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 received along this program for more
 * details (or else see http://www.gnu.org/licenses/).
 *
 *
 * This file is a part of jCumulus.
 */

import com.jcumulus.server.rtmfp.D;
import com.jcumulus.server.rtmfp.packet.*;
import com.jcumulus.server.rtmfp.pipe.C;
import com.jcumulus.server.rtmfp.application.VideoWriter;

import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;



public class FlowWriter
{
    private static final Logger G = Logger.getLogger(FlowWriter.class);
    private static J S = new J();
    private int J;
    private boolean K;
    private int C;
    private byte I[];
    private D H;
    private boolean B;
    private L A;
    private final List P = new ArrayList();
    private int N;
    private final List O = new ArrayList();
    private int L;
    private int M;
    private int D;
    private int F;
    private Double E;
    private String R;
    private int Q;



    public FlowWriter(byte abyte0[], D d)
    {
        A = new L();
        K = false;
        J = 0;
        N = 0;
        L = 0;
        B = false;
        E = Double.valueOf(0.0D);
        Q = 0;
        C = 0;
        H = d;
        I = abyte0;
        F = 0;
        M = 0;
        D = 0;
        d.B(this);
    }

    public com.jcumulus.server.rtmfp.application.AudioWriter B()
    {
        return new com.jcumulus.server.rtmfp.application.AudioWriter(I, H);
    }

    public VideoWriter K()
    {
        return new VideoWriter(I, H);
    }

    public void F()
    {
        B = true;
        I();
    }

    public void D(String s)
    {
        G.warn((new StringBuilder()).append("FlowWriter ").append(J).append(" has failed : ").append(s).toString());
        N = L = M = D = 0;
        I();
        if(B)
        {
            return;
        } else
        {
            H.B(this);
            return;
        }
    }

    public void I()
    {
    }

    public void C()
    {
        if(B)
            return;
        if(N > 0)
            if(D() != 0);
        B = true;
        A();
    }

    protected com.jcumulus.server.rtmfp.flow.A C(String s, String s1)
    {
        return A("_result", s, s1);
    }

    public com.jcumulus.server.rtmfp.flow.A A(String s, String s1)
    {
        return A("onStatus", s, s1);
    }

    public com.jcumulus.server.rtmfp.flow.A B(String s, String s1)
    {
        return A("_error", s, s1);
    }

    public void A(AudioPacket a)
    {
        int i = a.J();
        if(i == 0)
        {
            G.error("Negative acknowledgment");
            D("Negative acknowledgment");
            return;
        }
        int j = L;
        int k = a.J();
        int l = L + 1;
        if(k > N)
        {
            G.error((new StringBuilder()).append("Acknowledgment received ").append(k).append(" superior than the current sending stage ").append(N).append(" on flowWriter ").append(J).toString());
            L = N;
        } else
        if(k <= L)
        {
            if(a.I() == 0)
                G.debug((new StringBuilder()).append("Acknowledgment ").append(k).append(" obsolete on flowWriter ").append(J).toString());
        } else
        {
            L = k;
        }
        int i1 = L;
        int j1 = a.H();
        while(a.I() > 0)
            i1 += a.J() + a.J() + 2;
        if(j1 != a.H())
            a.E(j1);
        int k1 = 0;
        int l1 = 0;
        boolean flag = false;
        boolean flag1 = true;
        boolean flag2 = false;
        synchronized(O)
        {
            ListIterator listiterator = O.listIterator();
            do
            {
                if(flag2 || !listiterator.hasNext())
                    break;
                I i2 = (I)listiterator.next();
                if(i2.B().size() == 0)
                {
                    G.error((new StringBuilder()).append("Message ").append(l + 1).append(" is bad formatted on flowWriter ").append(J).toString());
                } else
                {
                    Integer ainteger[] = (Integer[])i2.B().keySet().toArray(new Integer[0]);
                    Integer integer = ainteger[0];
                    int j2 = 0;
                    do
                    {
                        if(j2 >= ainteger.length)
                            break;
                        if(L >= l)
                        {
                            i2.B().remove(ainteger[0]);
                            ainteger = (Integer[])i2.B().keySet().toArray(new Integer[0]);
                            j2 = 0;
                            if(j2 < ainteger.length)
                                integer = ainteger[j2];
                            D++;
                            l++;
                            continue;
                        }
                        do
                        {
                            if(flag2 || k1 != 0)
                                break;
                            if(k1 == 0)
                                if(a.I() > 0)
                                {
                                    k1 = a.J() + 1;
                                    l1 = k + 1;
                                    k = l1 + k1 + a.J();
                                } else
                                {
                                    flag2 = true;
                                    break;
                                }
                            if(l1 > N)
                            {
                                G.error((new StringBuilder()).append("Lost information received ").append(l1).append(" have not been yet sent on flowWriter ").append(J).toString());
                                flag2 = true;
                                break;
                            }
                            if(l1 > L)
                                break;
                            k1--;
                            l1++;
                        } while(true);
                        if(flag2)
                            break;
                        if(l1 != l)
                        {
                            if(flag)
                            {
                                l++;
                                if(j2 < ainteger.length - 1)
                                {
                                    j2++;
                                    integer = ainteger[j2];
                                }
                                flag1 = true;
                            } else
                            {
                                L = l;
                            }
                        } else
                        if(!i2.A())
                        {
                            if(flag)
                            {
                                j2++;
                                integer = ainteger[j2];
                                l++;
                                flag1 = true;
                            } else
                            {
                                G.debug((new StringBuilder()).append("FlowWriter ").append(J).append(" : message ").append(l).append(" lost").toString());
                                D--;
                                M++;
                                L = l;
                            }
                            k1--;
                            l1++;
                        } else
                        {
                            flag = true;
                            if(((Integer)i2.B().get(integer)).intValue() >= i1 || k == l1 + 2)
                            {
                                l++;
                                flag1 = true;
                                k1--;
                                l1++;
                                if(j2 < ainteger.length - 1)
                                {
                                    j2++;
                                    integer = ainteger[j2];
                                }
                            } else
                            {
                                G.debug((new StringBuilder()).append("FlowWriter ").append(J).append(" : stage ").append(l).append(" repeated").toString());
                                int k2 = integer.intValue();
                                Packet b1 = i2.A(k2);
                                int i3 = b1.I();
                                i2.B().put(integer, Integer.valueOf(N));
                                int j3 = i3;
                                byte byte0 = 0;
                                if(k2 > 0)
                                    byte0 |= com.jcumulus.server.rtmfp.publisher.E.M.intValue();
                                if(j2 < ainteger.length - 1)
                                {
                                    j2++;
                                    integer = ainteger[j2];
                                    byte0 |= com.jcumulus.server.rtmfp.publisher.E.C.intValue();
                                    j3 = integer.intValue() - k2;
                                }
                                com.jcumulus.server.rtmfp.stream.B b2 = H.B();
                                int k3 = j3 + 4;
                                if(!flag1 && k3 > b2.D())
                                {
                                    H.A(false);
                                    flag1 = true;
                                }
                                if(flag1)
                                    k3 += D(l);
                                if(k3 > b2.D())
                                    H.A(false);
                                k3 -= 3;
                                A(H.A(((byte)(flag1 ? 16 : 17)), k3, null), l, byte0, flag1, b1, j3);
                                i3 -= j3;
                                flag1 = false;
                                k1--;
                                l1++;
                                l++;
                            }
                        }
                    } while(true);
                    if(i2.B().size() == 0)
                    {
                        if(i2.A())
                            F--;
                        if(D > 0)
                        {
                            Packet b = i2.D();
                            int l2 = b.I();
                            A(D, M, b, l2);
                            D = M = 0;
                        }
                        listiterator.remove();
                    }
                }
            } while(true);
        }
        if(k1 > 0 && a.I() > 0)
            G.error((new StringBuilder()).append("Some lost information received have not been yet sent on flowWriter ").append(J).toString());
        if(F == 0)
            A.B();
        else
        if(L > j || flag)
            A.A();
    }

    public void A(int i)
    {
        if(i >= D())
        {
            G.error((new StringBuilder()).append("Impossible to cancel ").append(i).append(" message on flowWriter ").append(J).toString());
            return;
        }
        synchronized(P)
        {
            for(int j = i; j < P.size(); j++)
                P.remove(i);

        }
    }

    public void A(byte abyte0[], int i)
    {
        A(abyte0, i, ((byte []) (null)), 0);
    }

    public void A(byte abyte0[], int i, byte abyte1[], int j)
    {
        if(B || I == null || H.A())
            return;
        G g = new G(abyte0, i, abyte1, j);
        synchronized(P)
        {
            P.add(g);
        }
        A();
    }

    private K H()
    {
        if(B || I == null || H.A())
            return S;
        K k = new K();
        synchronized(P)
        {
            P.add(k);
        }
        return k;
    }

    public com.jcumulus.server.rtmfp.stream.BinaryWriter A(boolean flag)
    {
        K k = H();
        if(!flag)
        {
            k.E().B((byte)4);
            k.E().A(0);
        }
        return k.E();
    }

    public com.jcumulus.server.rtmfp.flow.F B(String s)
    {
        K k = H();
        k.E().B((byte)15);
        k.E().B((byte)0);
        k.E().A(0);
        k.F().A(s);
        return k.F();
    }

    private void A(com.jcumulus.server.rtmfp.stream.BinaryWriter a, String s, double d)
    {
        a.B((byte)20);
        a.A(0);
        a.B((byte)2);
        a.D(s.getBytes());
        a.B((byte)0);
        a.A(d);
        a.B((byte)5);
    }

    public com.jcumulus.server.rtmfp.flow.F A(String s)
    {
        K k = H();
        A(k.E(), s, 0.0D);
        return k.F();
    }

    public com.jcumulus.server.rtmfp.flow.F J()
    {
        K k = H();
        A(k.E(), "_result", E.doubleValue());
        return k.F();
    }

    com.jcumulus.server.rtmfp.flow.A A(String s, String s1, String s2)
    {
        K k = H();
        A(k.E(), s, E.doubleValue());
        String s3 = R;
        if(!Strings.isNullOrEmpty(s1))
        {
            s3 = (new StringBuilder()).append(s3).append(".").toString();
            s3 = (new StringBuilder()).append(s3).append(s1).toString();
        }
        boolean flag = k.F().D();
        k.F().B(true);
        com.jcumulus.server.rtmfp.flow.A a = new com.jcumulus.server.rtmfp.flow.A(k.F());
        if(s.equals("_error"))
            a.A("level", "error");
        else
            a.A("level", "status");
        a.A("code", s3);
        if(!Strings.isNullOrEmpty(s2))
            a.A("description", s2);
        k.F().B(flag);
        return a;
    }

    public void A()
    {
        B(false);
    }

    public void B(boolean flag)
    {
        boolean flag1 = !H.A(this);
        synchronized(P)
        {
            for(Iterator iterator = P.iterator(); iterator.hasNext();)
            {
                I i = (I)iterator.next();
                if(i.A())
                {
                    F++;
                    A.C();
                }
                int j = 0;
                Packet b = i.D();
                int k = b.I();
                do
                {
                    com.jcumulus.server.rtmfp.stream.B b1 = H.B();
                    if(b1.D() < 12)
                    {
                        H.A(false);
                        flag1 = true;
                    }
                    boolean flag2 = flag1;
                    int l = k;
                    int i1 = l + 4;
                    N++;
                    if(flag2)
                        i1 += D(N);
                    byte byte0 = 0;
                    if(j > 0)
                        byte0 |= com.jcumulus.server.rtmfp.publisher.E.M.intValue();
                    if(i1 > b1.D())
                    {
                        byte0 |= com.jcumulus.server.rtmfp.publisher.E.C.intValue();
                        l = b1.D() - (i1 - l);
                        i1 = b1.D();
                        flag1 = true;
                    } else
                    {
                        flag1 = false;
                    }
                    i1 -= 3;
                    A(H.A(((byte)(flag2 ? 16 : 17)), (short)i1, this), N, byte0, flag2, b, l);
                    i.B().put(Integer.valueOf(j), Integer.valueOf(N));
                    k -= l;
                    j += l;
                } while(k > 0);
                synchronized(O)
                {
                    O.add(i);
                }
            }

            P.clear();
        }
        if(flag)
            H.A(true);
    }

    int D(int i)
    {
        int j = com.jcumulus.server.rtmfp.pipe.C.A(J);
        j += com.jcumulus.server.rtmfp.pipe.C.A(i);
        if(L > i)
            G.error((new StringBuilder()).append("stageAck ").append(L).append(" superior to stage ").append(i).append(" on flowWriter ").append(J).toString());
        j += com.jcumulus.server.rtmfp.pipe.C.A(i - L);
        j += L <= 0 ? I.length + (C != 0 ? 4 + com.jcumulus.server.rtmfp.pipe.C.A(C) : 2) : 0;
        return j;
    }

    public void A(com.jcumulus.server.rtmfp.stream.B b, int i, byte byte0, boolean flag, Packet b1, int j)
    {
        if(L == 0 && flag)
            byte0 |= com.jcumulus.server.rtmfp.publisher.E.N.intValue();
        if(j == 0)
            byte0 |= com.jcumulus.server.rtmfp.publisher.E.H.intValue();
        if(B)
            byte0 |= com.jcumulus.server.rtmfp.publisher.E.E.intValue();
        G.debug((new StringBuilder()).append("FlowWriter ").append(J).append(" stage ").append(i).toString());
        b.B(byte0);
        if(flag)
        {
            b.D(J);
            b.D(i);
            b.D((byte0 & com.jcumulus.server.rtmfp.publisher.E.H.intValue()) == 0 ? i - L : 0);
            if(L == 0)
            {
                b.C(I);
                if(C > 0)
                {
                    b.B((byte)(1 + com.jcumulus.server.rtmfp.pipe.C.A(C)));
                    b.B((byte)10);
                    b.D(C);
                }
                b.B((byte)0);
            }
        }
        if(j > 0)
            b.B(b1.F(j));
    }

    protected void A(int i, int j, Packet b, int k)
    {
    }

	public int D()
	{
		synchronized (this.P)
		{
		  return this.P.size();
		}
	}

    public int E()
    {
        return J;
    }

    public void B(int i)
    {
        J = i;
    }

    public void C(int i)
    {
        C = i;
    }

    public void C(String s)
    {
        R = s;
    }

    public void A(Double double1)
    {
        E = double1;
    }

    public byte[] G()
    {
        return I;
    }

}
