// project created on 04.04.2006 at 22:51
//#define DEBUG_MSG

using System;
using System.IO;

class MP3Rec
    {
    public MP3Rec  Next;
    public MP3Rec  Prev;    // nur in DLL verwendet
    public string Interpret;
    public string Titel;
    public string Album;
    public int nkBitRate;
    }

class MainClass
    {
    // Konstanten
    const string INFILE_PATH = "/home/cbx/FH/SE_2006_SS/web/mp3liste_unsorted.txt";

    public enum ListMode {SingleUnsorted, SingleSorted, DoubleUnsorted, DoubleSorted};

    // schmutzige Member
    static int nCounter = 0;

//*********************************************************************
// Main()

    public static void Main(string[] args)
        {
        MP3Rec HeadSllUnsorted = new MP3Rec();
        MP3Rec HeadSllSorted   = new MP3Rec();
        MP3Rec HeadDllUnsorted = new MP3Rec();
        MP3Rec HeadDllSorted   = new MP3Rec();
        int nRecords;
        DateTime startTime, stopTime;
        TimeSpan duration;
        
        Console.WriteLine("The MP3-DB");
        
        startTime = DateTime.Now;
        
        nRecords = MP3FileListRead(HeadSllUnsorted, INFILE_PATH, ListMode.SingleUnsorted);
        stopTime = DateTime.Now;
        duration = stopTime - startTime;
        Console.WriteLine("Read and enqueued {0} Records in {1} Seconds.",nRecords, duration.TotalSeconds);

        startTime = DateTime.Now;
        nRecords = MP3FileListRead(HeadSllSorted, INFILE_PATH, ListMode.SingleSorted);
        stopTime = DateTime.Now;
        duration = stopTime - startTime;
        Console.WriteLine("Read and sorted {0} Records in {1} Seconds.",nRecords, duration.TotalSeconds);

        startTime = DateTime.Now;
        nRecords = MP3FileListRead(HeadDllUnsorted, INFILE_PATH, ListMode.DoubleUnsorted);
        stopTime = DateTime.Now;
        duration = stopTime - startTime;
        Console.WriteLine("Read and enqueued {0} Records in {1} Seconds.",nRecords, duration.TotalSeconds);

        startTime = DateTime.Now;
        nRecords = MP3FileListRead(HeadDllSorted, INFILE_PATH, ListMode.DoubleSorted);
        stopTime = DateTime.Now;
        duration = stopTime - startTime;
        Console.WriteLine("Read and sorted {0} Records in {1} Seconds.",nRecords, duration.TotalSeconds);
        
        Console.WriteLine("\n***********************************\n");
                
        // herzeigen...?
        MP3ListTraverseShow(HeadDllSorted, 50);
        MP3ListTraverseCount(HeadSllUnsorted);      
        }
        
//*********************************************************************
// Das gesamte File einlesen
    public static int MP3FileListRead(MP3Rec Head, string strFile, ListMode Mode)
        {
        StreamReader inStream;
        int nRecsRead = 0;
        MP3Rec Cur = Head;
        
        try 
            {
            inStream = new StreamReader(strFile);
            // Titelzeile ignorieren
            inStream.ReadLine();
            
            MP3Rec listRec;

            nCounter = 0;
            
            while ((listRec = MP3RecordRead(inStream)) != null)
                {
                nRecsRead++;
                switch (Mode)
                    {
                    case ListMode.SingleUnsorted: 
                        Cur = MP3ListEnqueueTail(Head,Cur,listRec);
                        break;

                    case ListMode.SingleSorted:     
                        Cur = MP3ListEnqueueSortTitle(Head,Cur,listRec,ListMode.SingleSorted);
                        break;

                    case ListMode.DoubleUnsorted: 
                        Cur = MP3ListEnqueueTailDouble(Head,Cur,listRec);
                        break;

                    case ListMode.DoubleSorted: 
                        Cur = MP3ListEnqueueSortTitle(Head,Cur,listRec,ListMode.DoubleSorted);
                        break;
                        
                    }
                    
#if DEBUG_MSG
                // damit mer net ersaufen...
                if (nRecsRead > 20) break;
#endif
                }
            }
        // einzig handelbarer Fall: Das file gibts nicht => schulfrei!  
        catch (FileNotFoundException ex)
            {
            Console.WriteLine("File not found...");
            return 0;
            }
        
        inStream.Close();
        
        Console.WriteLine("This took {0} Node accesses to enqueue {1} Records", nCounter, nRecsRead);
        Console.WriteLine("Square of Records/2 is {0}.",(nRecsRead/2)*(nRecsRead/2));
        return nRecsRead;   
        }

//*********************************************************************
// Einfach am Arsch der Liste anhängen und den neuen Arsch zurückgeben 
    public static MP3Rec MP3ListEnqueueTail(MP3Rec Head, MP3Rec Tail, MP3Rec New)
        {
        Tail.Next = New;
        New.Next  = null;
        nCounter++;
        return New;
        }

//*********************************************************************
// Einfach am Arsch der Liste anhängen und den neuen Arsch zurückgeben 
    public static MP3Rec MP3ListEnqueueTailDouble(MP3Rec Head, MP3Rec Tail, MP3Rec New)
        {
        Tail.Next = New;
        New.Prev  = Tail; // zurück verweisen
        nCounter++;
        return New;
        }

//*********************************************************************
// Nach Titel sortiert in die liste hängen 
    public static MP3Rec MP3ListEnqueueSortTitle(MP3Rec Head, MP3Rec Tail, MP3Rec New, ListMode Mode)
        {
        MP3Rec Cur, Prev;

#if DEBUG_MSG
        Console.WriteLine("Enqueuing {0}", New.Titel);      
#endif

        // Sonderfall ganz Leere Liste: Der erste node darf unconditional dran
        if (Head.Next == null)
            {
            if (Mode == ListMode.SingleSorted)
                {
                Head.Next = New;
                New.Next  = null;
                }
            else
                {
                Head.Next = New;
                New.Next  = null;
                New.Prev  = Head;
                }   
#if DEBUG_MSG
            Console.WriteLine("Enqueued {0} in empty List", New.Titel);     
#endif
            nCounter++;
            return New;
            }
        // Regulärer Fall: nicht leere Liste
        // Von vorne durch die Liste gehen und dort wo wir nicht mehr kleiner sind, einsortieren 
        for ( Cur = Head.Next, Prev = Head ; Cur != null ; Cur = Cur.Next )
            {
            // einen Zugriff zählen
            nCounter++;

            // vergleichen, ob der aktuelle Node hinter dem neuen kommt
            if (String.Compare (Cur.Titel, New.Titel, true ) > 0)
                {
                // dann davor einsortiern. Gut dass wir den um eins nacheilenden <Prev> haben!
                if (Mode == ListMode.SingleSorted)
                    {
                    // zwei mal umbiegen
                    Prev.Next = New; // mich selbst beim Vordermann eintragen
                    New.Next  = Cur; // Und den aktuellen als meinen Nachfolger
                    }
                else    
                    {
                    // vier mal umbiegen
                    New.Next  = Cur;
                    New.Prev  = Cur.Prev; // Prev;

                    Cur.Prev.Next = New;
                    Cur.Prev = New; 
                    } 

#if DEBUG_MSG
                Console.WriteLine("Enqueued {0} before {1}", New.Titel, Cur.Titel );        
#endif
                break;
                }
            else
                {
                // sonst wars nix
#if DEBUG_MSG
                Console.WriteLine("Compared {0} to {1}", New.Titel, Cur.Titel );        
#endif
                }               

            // schon am Ende? Am Ende anhängen
            if (Cur.Next == null)   
                {
                if (Mode == ListMode.SingleSorted)
                    {
                    New.Next = Cur.Next;
                    Cur.Next = New;
                    }
                else
                    {
                    // vier mal umbiegen
                    New.Next = Cur.Next;
                    New.Prev = Cur;

                    Cur.Next = New;                 
                    } 
                        
#if DEBUG_MSG
                Console.WriteLine("Enqueued {0} as Tail", New.Titel);       
#endif
                break; 
                }
                
                
            // Der lauft eins hinterher 
            Prev = Cur; 
            }

#if DEBUG_MSG
        Console.WriteLine("Successfully Enqueued {0}.", New.Titel);     
#endif
        return New;
        }

//*********************************************************************
// Einen Datensatz einlesen...
    public static MP3Rec MP3RecordRead(StreamReader inStream)
        {
        string strLine = inStream.ReadLine();
        
        if (strLine != null)
            {
            string[] strParts = strLine.Split('\t');
            MP3Rec readRec = new MP3Rec();

            readRec.Next      = null;
            readRec.Prev      = null;

            readRec.Interpret = strParts[0].Trim('"').TrimStart(' ','_');
            readRec.Titel     = strParts[1].Trim('"').TrimStart(' ','_');
            readRec.Album     = strParts[2].Trim('"').TrimStart(' ','_');
            
            if (strParts[3].Length > 3)
                readRec.nkBitRate = Convert.ToInt32( strParts[3].Trim('"').Split('k','K')[0] );
            else        
                readRec.nkBitRate = 128;
            return readRec;
            }
        else
            return null;
        } 

//*********************************************************************
    public static void MP3ListTraverseShow(MP3Rec Head, int nMenge)
        {
        int i=0;
        
        for ( MP3Rec Cur = Head.Next ; Cur != null; Cur = Cur.Next )
            {
            Console.WriteLine("\"{0}\"\tby >{1}<\tfrom \"{2}\"\tat {3}kBps",
                                Cur.Titel, Cur.Interpret,
                                Cur.Album, Cur.nkBitRate );
            if ( nMenge > 0 )
                if (++i >= nMenge)
                    break;
            }
        }

//*********************************************************************
    public static void MP3ListTraverseCount(MP3Rec Head)
        {
        int nSongs192k = 0;
        int nSongsWithLove = 0;
        int nSongsWithLiebe = 0;
        int nRate;
        int[] anBitraten = new int[325];
        
        for ( MP3Rec Cur = Head.Next ; Cur != null; Cur = Cur.Next )
            {
            if (Cur.nkBitRate == 192)
                nSongs192k++;
            
            if (Cur.Titel.ToLower().IndexOf("love") >= 0)
                nSongsWithLove++;

            if (Cur.Titel.ToLower().IndexOf("liebe") >= 0)
                nSongsWithLiebe++;
            
            nRate = Cur.nkBitRate;  
            if (nRate < 64)
                nRate = 63;
            else if (nRate > 320)
                nRate = 321;
            
            anBitraten[nRate]++;
            }

        Console.WriteLine("\nUnd hier die Auswertung:\n");
        Console.WriteLine("Es sind {0} Songs mit 192kBps, {1} Songs mit \"love\" und {2} Songs mit \"Liebe\"\n",
                            nSongs192k, nSongsWithLove, nSongsWithLiebe );

        Console.WriteLine("Es sind {0} Songs unter 64kBps",anBitraten[63]);

        for (int nBitrate = 64; nBitrate <= 320 ; nBitrate++)
            {
            if (anBitraten[nBitrate] > 0)
                {
                Console.WriteLine("Es sind {0} Songs mit {1}kBps",anBitraten[nBitrate],nBitrate);
                }
            }
        Console.WriteLine("Es sind {0} Songs über 320kBps",anBitraten[321]);
        }

    } //class

syntax highlighted by Code2HTML, v. 0.9.1