/*
 *  Class TestMPEGTables
 *
 *  Copyright (C) Karl Dietz 2013
 *
 *   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 2 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 for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include <QtTest/QtTest>

#include "mpegtables.h"
#include "dvbtables.h"

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#define MSKIP(MSG) QSKIP(MSG, SkipSingle)
#else
#define MSKIP(MSG) QSKIP(MSG)
#endif

class TestMPEGTables: public QObject
{
    Q_OBJECT

  private slots:
    void pat_test(void)
    {
        const unsigned char si_data[] = {
            0x00, 0xb0, 0x31, 0x04, 0x37, 0xdf, 0x00, 0x00,  0x2b, 0x66, 0xf7, 0xd4, 0x6d, 0x66, 0xe0, 0x64,  /* ..1.7...+f..mf.d */
            0x6d, 0x67, 0xe0, 0xc8, 0x6d, 0x68, 0xe1, 0x2c,  0x6d, 0x6b, 0xe2, 0x58, 0x6d, 0x6c, 0xe2, 0xbc,  /* mg..mh.,mk.Xml.. */
            0x6d, 0x6d, 0xe3, 0x20, 0x6d, 0x6e, 0xe2, 0x8a,  0x6d, 0x70, 0xe4, 0x4c, 0x6d, 0x71, 0xe1, 0x9b,  /* mm. mn..mp.Lmq.. */
            0xc0, 0x79, 0xa6, 0x2b                                                                            /* .y.+ */
        };

        PSIPTable si_table(si_data);

        QVERIFY  (si_table.IsGood());

        ProgramAssociationTable pat = si_table;

        QVERIFY  (pat.HasCRC());
        QVERIFY  (pat.VerifyCRC());
        QCOMPARE (si_table.Length(),       (uint32_t)  0x31);
        QCOMPARE (pat.Length(),            (uint32_t)    49);
        QCOMPARE (pat.SectionLength(),     (uint32_t)    49+3);
        QCOMPARE (pat.TransportStreamID(), (uint32_t)  1079);
        QCOMPARE (pat.ProgramCount(),      (uint32_t)    10);

        QCOMPARE (pat.ProgramNumber(0),    (uint32_t) 11110);
        QCOMPARE (pat.ProgramPID(0),       (uint32_t)  6100);

        QCOMPARE (pat.ProgramNumber(1),    (uint32_t) 28006);
        QCOMPARE (pat.ProgramPID(1),       (uint32_t)   100);

        QCOMPARE (pat.ProgramNumber(2),    (uint32_t) 28007);
        QCOMPARE (pat.ProgramPID(2),       (uint32_t)   200);

        QCOMPARE (pat.ProgramNumber(3),    (uint32_t) 28008);
        QCOMPARE (pat.ProgramPID(3),       (uint32_t)   300);

        QCOMPARE (pat.ProgramNumber(4),    (uint32_t) 28011);
        QCOMPARE (pat.ProgramPID(4),       (uint32_t)   600);

        QCOMPARE (pat.ProgramNumber(5),    (uint32_t) 28012);
        QCOMPARE (pat.ProgramPID(5),       (uint32_t)   700);

        QCOMPARE (pat.ProgramNumber(6),    (uint32_t) 28013);
        QCOMPARE (pat.ProgramPID(6),       (uint32_t)   800);

        QCOMPARE (pat.ProgramNumber(7),    (uint32_t) 28014);
        QCOMPARE (pat.ProgramPID(7),       (uint32_t)   650);

        QCOMPARE (pat.ProgramNumber(8),    (uint32_t) 28016);
        QCOMPARE (pat.ProgramPID(8),       (uint32_t)  1100);

        QCOMPARE (pat.ProgramNumber(9),    (uint32_t) 28017);
        QCOMPARE (pat.ProgramPID(9),       (uint32_t)   411);

        // go out of bounds and see what happens if we parse the CRC
        QCOMPARE (pat.ProgramNumber(10) << 16 | pat.ProgramPID(10), pat.CRC() & 0xFFFF1FFF);

        QCOMPARE (pat.FindPID(11110),      (uint32_t)  6100); // the first
        QCOMPARE (pat.FindPID(28017),      (uint32_t)   411); // the last
        QCOMPARE (pat.FindPID(28008),      (uint32_t)   300); // random one
        QCOMPARE (pat.FindPID(12345),      (uint32_t)     0); // not found

        QCOMPARE (pat.FindProgram(6100),   (uint32_t) 11110); // the first
        QCOMPARE (pat.FindProgram(411),    (uint32_t) 28017); // the last
        QCOMPARE (pat.FindProgram(300),    (uint32_t) 28008); // random one
        QCOMPARE (pat.FindProgram(12345),  (uint32_t)     0); // not found

        // first PID that is a real PMT PID and not the NIT PID
        QCOMPARE (pat.FindAnyPID(),        (uint32_t)  6100);
    }

    void dvbdate(void)
    {
        unsigned char dvbdate_data[] = {
            0xdc, 0xa9, 0x12, 0x33, 0x37 /* day 0xdca9, 12:33:37 UTC */
        };

        QCOMPARE (dvbdate2unix (dvbdate_data), (time_t) 1373978017);
        QCOMPARE (dvbdate2qt (dvbdate_data), MythDate::fromString("2013-07-16 12:33:37 Z"));
    }

    void tdt_test(void)
    {
        const unsigned char si_data[] = {
            0x70, 0x70, 0x05, 0xdc, 0xa9, 0x12, 0x33, 0x37                                                    /* pp....37 */
        };

        PSIPTable si_table(si_data);

//      test for the values needed for the copy constructor, especially the length
//        QCOMPARE (si_table._pesdataSize, 8); // is protected, so use TSSizeInBuffer() instead
        QCOMPARE (si_table.TSSizeInBuffer(), (unsigned int) 8);

        TimeDateTable tdt = si_table;

        QVERIFY  (tdt.IsGood());

        QVERIFY  (!tdt.HasCRC());
        QVERIFY  (tdt.VerifyCRC());

        for (size_t i=0; i<5; i++) {
            QCOMPARE (si_table.pesdata()[i+3], (uint8_t) si_data[i+3]);
        }

        const unsigned char *dvbDateBuf = tdt.UTCdata();

        for (size_t i=0; i<5; i++) {
            QCOMPARE (dvbDateBuf[i], (uint8_t) si_data[i+3]);
        }

        // actual is 2013-03-30 01:00:00 UTC, 24 hours before the switch to DST in europe
        QCOMPARE (tdt.UTCUnix(), (time_t) 1373978017);
        QCOMPARE (tdt.UTC(), MythDate::fromString("2013-07-16 12:33:37 Z"));
    }

    void ContentIdentifierDescriptor_test(void)
    {
        const unsigned char eit_data[] = {
            0x4f, 0xf2, 0x17, 0x42, 0xd8, 0xdb, 0x00, 0x01,  0x00, 0xab, 0x27, 0x0f, 0x01, 0x4f, 0x30, 0x17,  /* O..B......'..O0. */
            0xdc, 0xc9, 0x07, 0x15, 0x00, 0x00, 0x25, 0x00,  0x81, 0xfc, 0x4d, 0xb2, 0x65, 0x6e, 0x67, 0x0d,  /* ......%...M.eng. */
            0x05, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x62, 0x72,  0x6f, 0x74, 0x68, 0x65, 0x72, 0xa0, 0x05, 0x44,  /* .Moneybrother..D */
            0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61,  0x72, 0x79, 0x20, 0x73, 0x65, 0x72, 0x69, 0x65,  /* ocumentary serie */
            0x73, 0x20, 0x6f, 0x6e, 0x20, 0x53, 0x77, 0x65,  0x64, 0x65, 0x6e, 0x27, 0x73, 0x20, 0x41, 0x6e,  /* s on Sweden's An */
            0x64, 0x65, 0x72, 0x73, 0x20, 0x57, 0x65, 0x6e,  0x64, 0x69, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20,  /* ders Wendin and  */
            0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x6b, 0x69,  0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x68, 0x69,  /* the making of hi */
            0x73, 0x20, 0x6e, 0x65, 0x77, 0x20, 0x61, 0x6c,  0x62, 0x75, 0x6d, 0x2e, 0x20, 0x54, 0x68, 0x69,  /* s new album. Thi */
            0x73, 0x20, 0x65, 0x70, 0x69, 0x73, 0x6f, 0x64,  0x65, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x73, 0x20,  /* s episode shows  */
            0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x65, 0x70,  0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,  /* the preparation  */
            0x69, 0x6e, 0x20, 0x53, 0x74, 0x6f, 0x63, 0x6b,  0x68, 0x6f, 0x6c, 0x6d, 0x20, 0x61, 0x6e, 0x64,  /* in Stockholm and */
            0x20, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69,  0x6e, 0x67, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x43,  /*  recordings in C */
            0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x20, 0x61,  0x6e, 0x64, 0x20, 0x4c, 0x41, 0x2e, 0x4d, 0xc7,  /* hicago and LA.M. */
            0x67, 0x65, 0x72, 0x0d, 0x05, 0x4d, 0x6f, 0x6e,  0x65, 0x79, 0x62, 0x72, 0x6f, 0x74, 0x68, 0x65,  /* ger..Moneybrothe */
            0x72, 0xb5, 0x05, 0x44, 0x69, 0x65, 0x73, 0x65,  0x20, 0x46, 0x6f, 0x6c, 0x67, 0x65, 0x20, 0x64,  /* r..Diese Folge d */
            0x65, 0x73, 0x20, 0x4d, 0x75, 0x73, 0x69, 0x6b,  0x6d, 0x61, 0x67, 0x61, 0x7a, 0x69, 0x6e, 0x73,  /* es Musikmagazins */
            0x20, 0x6d, 0x69, 0x74, 0x20, 0x64, 0x65, 0x6d,  0x20, 0x73, 0x63, 0x68, 0x77, 0x65, 0x64, 0x69,  /*  mit dem schwedi */
            0x73, 0x63, 0x68, 0x65, 0x6e, 0x20, 0x4d, 0x75,  0x73, 0x69, 0x6b, 0x65, 0x72, 0x20, 0x41, 0x6e,  /* schen Musiker An */
            0x64, 0x65, 0x72, 0x73, 0x20, 0x57, 0x65, 0x6e,  0x64, 0x69, 0x6e, 0x20, 0x61, 0x2e, 0x6b, 0x2e,  /* ders Wendin a.k. */
            0x61, 0x2e, 0x20, 0x4d, 0x6f, 0x6e, 0x65, 0x79,  0x62, 0x72, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,  /* a. Moneybrother  */
            0x7a, 0x65, 0x69, 0x67, 0x74, 0x20, 0x64, 0x69,  0x65, 0x20, 0x56, 0x6f, 0x72, 0x62, 0x65, 0x72,  /* zeigt die Vorber */
            0x65, 0x69, 0x74, 0x75, 0x6e, 0x67, 0x65, 0x6e,  0x20, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x6f, 0x63,  /* eitungen in Stoc */
            0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x20, 0x75, 0x6e,  0x64, 0x20, 0x64, 0x69, 0x65, 0x20, 0x65, 0x72,  /* kholm und die er */
            0x73, 0x74, 0x65, 0x6e, 0x20, 0x41, 0x75, 0x66,  0x6e, 0x61, 0x68, 0x6d, 0x65, 0x6e, 0x20, 0x43,  /* sten Aufnahmen C */
            0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x20, 0x75,  0x6e, 0x64, 0x20, 0x4c, 0x6f, 0x73, 0x20, 0x41,  /* hicago und Los A */
            0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x2e, 0x76,  0x73, 0x04, 0x40, 0x65, 0x76, 0x65, 0x6e, 0x74,  /* ngeles.vs.@event */
            0x69, 0x73, 0x2e, 0x6e, 0x6c, 0x2f, 0x30, 0x30,  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x30,  /* is.nl/00000000-0 */
            0x30, 0x30, 0x30, 0x2d, 0x31, 0x30, 0x30, 0x30,  0x2d, 0x30, 0x36, 0x30, 0x34, 0x2d, 0x30, 0x30,  /* 000-1000-0604-00 */
            0x30, 0x30, 0x30, 0x30, 0x30, 0x45, 0x30, 0x37,  0x31, 0x31, 0x23, 0x30, 0x30, 0x31, 0x30, 0x33,  /* 00000E0711#00103 */
            0x38, 0x39, 0x39, 0x30, 0x30, 0x30, 0x30, 0x32,  0x30, 0x31, 0x37, 0x08, 0x2f, 0x65, 0x76, 0x65,  /* 89900002017./eve */
            0x6e, 0x74, 0x69, 0x73, 0x2e, 0x6e, 0x6c, 0x2f,  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,  /* ntis.nl/00000000 */
            0x2d, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x31, 0x30,  0x30, 0x30, 0x2d, 0x30, 0x36, 0x30, 0x38, 0x2d,  /* -0000-1000-0608- */
            0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,  0x33, 0x46, 0x39, 0x43, 0x55, 0x04, 0x44, 0x45,  /* 000000003F9CU.DE */
            0x55, 0x00, 0x54, 0x02, 0x23, 0x00, 0x3b, 0xf9,  0x94, 0xa5                                       /* U.T.#.;...       */
        };

        /* pick just the ContentIdentifierDescriptor from the event_information_section */
        DVBContentIdentifierDescriptor descriptor(&eit_data[407]);

        QCOMPARE (descriptor.CRIDCount(),  (size_t) 2);
        QCOMPARE (descriptor.ContentId(),  QString("eventis.nl/00000000-0000-1000-0604-0000000E0711"));

        /* FIXME hack to test the case of no hash in the CRID until we support more then one CRID per descriptor */
        const unsigned char cid_data[] = {
            0x76, 0x31, 0x04, 0x2f, 0x65, 0x76, 0x65, 0x6e,  0x74, 0x69, 0x73, 0x2e, 0x6e, 0x6c, 0x2f, 0x30,  /* vs.@eventis.nl/0 */
            0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d,  0x30, 0x30, 0x30, 0x30, 0x2d, 0x31, 0x30, 0x30,  /* 0000000-0000-100 */
            0x30, 0x2d, 0x30, 0x36, 0x30, 0x38, 0x2d, 0x30,  0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33,  /* 0-0608-000000003 */
            0x46, 0x39, 0x43                                                                                  /* F9C              */
        };
        DVBContentIdentifierDescriptor descriptor2(cid_data);
        QCOMPARE (descriptor2.ContentId(), QString("eventis.nl/00000000-0000-1000-0608-000000003F9C"));
        QCOMPARE (descriptor.ContentId(1), QString("eventis.nl/00000000-0000-1000-0608-000000003F9C"));
    }
};
