// project created on 28.04.2006 at 13:42
using System;
using System.IO;

namespace uebung4_gr1
{

    class Song
    {
        public string Artist;
        public string Title;
        public string Album;
        public int    Rate;
        public string Path;

    }

    class Link
    {
        public Link next;
        public Link prev;
        public Link sub;
        public Song data;
    }

    class MainClass
        {

        public enum ListMode {listArtists, listAlbums, listTitles};
        public enum Dir {Left, Right};

        public static string SRC_PATH = "/home/cbx/FH/SE_2006_SS/web/mp3liste_unsorted_web.txt";
        
//****************************************************************************************************
            
        public static void Main(string[] args)
            {
            Link ListByArtists, ListByAlbums, ListByTitle;
            Link Root;
            Link Head = new Link();
            Link CurEnd;
            
                Console.WriteLine("Hello World!");

                Console.WriteLine("string.Compare( \"aal\" , \"Zipfel\", true ) = {0}",
                                   string.Compare( "Aal" , "Zipfel", true ));

                Root = MP3FileLoadToTree(SRC_PATH);
                
                if (null == Root)
                    {
                    Console.WriteLine("Voll krass die Scheisse");
                    return;
                    }
                                
                CurEnd = Head;
                
                MP3TreeIntraverseToList(Root, ref CurEnd);
                
                while (MP3FileDelKey(Root, "Britney Spears") > 0);              
                while (MP3FileDelKey(Root, "Enrique Iglesias") > 0);                
                while (MP3FileDelKey(Root, "Take That") > 0);               
                
                MP3TreeIntraverse(Root);
                
                /*
                ListByArtists = MP3RecordListSubList(Head, ListMode.listArtists);
                ListByAlbums  = MP3RecordListSubList(Head, ListMode.listAlbums);
                ListByTitle   = MP3RecordListSubList(Head, ListMode.listTitles);
            
                for (CurEnd = Head.next ; CurEnd != null ; CurEnd = CurEnd.next )
                    {
                    MP3RecordShow(CurEnd.data);
                    }
                */

            }

//****************************************************************************************************
            
        static public Link MP3FileLoadToTree(string strPfad)
            {
            StreamReader inStream;
            
            Link Root = null;

            try
                {
                inStream = new StreamReader(strPfad);
                }
            catch (FileNotFoundException ex)
                {
                Console.WriteLine("No file found. It wont work, sorry.");
                return null;
                }
            
            string strLine;
            
            // Titelzeile
            inStream.ReadLine();
            
            while ( (strLine = inStream.ReadLine()) != null ) 
                {
                Song curSong;
                curSong = MP3RecordParse(strLine);
                
                Root = MP3TreeAdd( Root, curSong);
                }
                
            inStream.Close();
            
            return Root;
            }
            

//****************************************************************************************************

public static Link MP3TreeAdd(Link Root, Song newSong)
    {
    
    if (Root == null)
        {
        // In den Baum inhängen
        Link newNode = new Link();
        
        newNode.data = newSong;
        
        return newNode;
        }
    else
        {
//      if (string.Compare( newSong.Title, Root.data.Title, true ) > 0)
        if (string.Compare( newSong.Artist, Root.data.Artist , true ) > 0)
            {
            // ist grösser: rechts / next anhängen
            Root.next = MP3TreeAdd(Root.next, newSong);
            }
        else
            {
            // ist grösser: links / prev anhängen
            Root.prev = MP3TreeAdd(Root.prev, newSong);
            }
        return Root;    
        }
    }
    
//****************************************************************************************************
    
public static void MP3TreeIntraverse(Link Root)
    {
    if (Root != null)
        {
        // ganz nach links
        MP3TreeIntraverse(Root.prev);
        MP3RecordShow(Root.data);
        MP3TreeIntraverse(Root.next);       
        }
    }

//****************************************************************************************************
    
public static void MP3TreeIntraverseToList(Link Root, ref Link ListEnd)
    {
    if (Root != null)
        {
        // ganz nach links
        MP3TreeIntraverseToList(Root.prev, ref ListEnd);
        
        // hinten anhängen heisst:
        
        // 1) Linkknoten erzeugen
        Link newNode = new Link();
        
        // 2) mit den Daten verbinden
        newNode.data = Root.data;
        
        // 3) Mit dem Listenede verketten
        ListEnd.next = newNode;
        
        // 4) zurückverketten
        newNode.prev = ListEnd;
        
        // 5) Listenende updaten
        ListEnd = newNode; 
        
        MP3TreeIntraverseToList(Root.next, ref ListEnd);        
        }
    }


//****************************************************************************************************
            
        static public Song MP3RecordParse(string strLine)
            {
            string[] astrElements;
            Song newSong = new Song();
      
            astrElements = strLine.Split('\t');

            newSong.Artist = astrElements[0].Trim('"',' ','_');
            newSong.Title  = astrElements[1].Trim('"',' ','_');
            newSong.Album  = astrElements[2].Trim('"',' ','_');
            newSong.Path   = astrElements[4].Trim('"',' ','_');
            
            if (astrElements[3].Length > 6)
                {
                newSong.Rate = Convert.ToInt32( astrElements[3].Split('K')[0].TrimStart('"') );
                }
            else
                {
                newSong.Rate = 128;
                }
                
            return newSong;
            }

//****************************************************************************************************
            
        static public void MP3RecordShow(Song thisSong)
            {
            Console.WriteLine(">{0}< by {2} @ {1} KBps",thisSong.Title, thisSong.Rate, thisSong.Artist );
            }

//****************************************************************************************************
            
        static public Link MP3RecordListSubList(Link MainList, ListMode eMode)
            {
            Link CurMain, CurArtist, PrevArtist;
            Link Cur;
            Link ArtistList = new Link();
            
            
            for (CurMain = MainList.next ; CurMain != null ; CurMain = CurMain.next )
                {
                for (CurArtist = ArtistList.next, PrevArtist = ArtistList ;
                        CurArtist != null ; PrevArtist = CurArtist, CurArtist = CurArtist.next )
                    {
                    
                    // Console.WriteLine("Processing {0} vs {1}", CurMain.data.Artist, CurArtist.data.Artist );
                    
                    int CompareResult;
                    
                    switch (eMode)
                        {
                        case ListMode.listAlbums:
                            CompareResult = string.Compare (CurMain.data.Album, CurArtist.data.Album, true);
                        break;

                        case ListMode.listArtists:
                            CompareResult = string.Compare (CurMain.data.Artist, CurArtist.data.Artist, true);
                        break;

                        case ListMode.listTitles:
                            CompareResult = string.Compare (CurMain.data.Title, CurArtist.data.Title, true);
                        break;
                        
                        default:
                            CompareResult = -2;
                        break;
                        }
                    
                    if (CompareResult == 0)
                        {
                        
                        // gibts schon. Neuen Titel in Liste einhängen
                        // Das Ende der Liste suchen. Es ist sichergestellt, dass der allererste
                        // Knoten schon an .sub dran hängt.
                        for (Cur = CurArtist.sub; Cur.next != null ; Cur = Cur.next ); // sic!
                        
                        // den nexsten Titel hinten an die subliste dran
                        Cur.next       = new Link();
                        Cur.next.data  = CurMain.data;
                        break;
                        }
                    }
                    
                if (CurArtist == null)  
                    {
                    Link newNode;
                    
                    // am Listenende anhängen
                    // neuen Node gleich anhängen
                    PrevArtist.next = newNode = new Link();
                    // rückwärts verlinken
                    newNode.prev = PrevArtist.next; //   <:-)
                    // Daten anhängen
                    newNode.data = CurMain.data; 
                    
                    // den ersten Titel auch gleich an die subliste
                    newNode.sub = new Link();
                    newNode.sub.data = CurMain.data;
                    }
                }
            
            // Kontrolle
            
            int  i;
            
            for (Cur = ArtistList.next, i=0; Cur != null; Cur = Cur.next, i++ )
                {
                switch (eMode)
                    {
                    case ListMode.listArtists: 
                        Console.WriteLine("*** {0} ***", Cur.data.Artist );
                    break;

                    case ListMode.listAlbums: 
                        Console.WriteLine("*** {0} ***", Cur.data.Album);
                    break;

                    case ListMode.listTitles: 
                        Console.WriteLine("*** {0} ***", Cur.data.Title);
                    break;
                    }
                        
                for (Link Tittel = Cur.sub ; Tittel != null; Tittel = Tittel.next )
                    {
                    switch (eMode)
                        {
                        case ListMode.listArtists: 
                            Console.WriteLine("\t{0} on {1}", Tittel.data.Title, Tittel.data.Album );
                        break;

                        case ListMode.listAlbums: 
                            Console.WriteLine("\t{0} by {1}", Tittel.data.Title, Tittel.data.Artist );
                        break;

                        case ListMode.listTitles: 
                            Console.WriteLine("\tfrom {0} by {1}", Tittel.data.Album, Tittel.data.Artist );
                        break;
                        }
                    }
                }
            
            Console.WriteLine("{0} Artists in total",i);

            return ArtistList;
    
            }

//****************************************************************************************************
            
static public int MP3FileDelKey(Link Root, string strName)

    {
    
    Link Cur, Prev, CurSymm, PrevSymm;
    int cnt=1;
    Dir dir = Dir.Left;
    
    Cur  = Root;
    Prev = Root;
    
    Console.WriteLine("===> Searching for {0}...",strName);
    
    while(Cur != null)
        {                                       // Schlüssel key suchen
        Console.Write("===> Compare {0} to {1} --> ",strName, Cur.data.Artist);
        
        if (string.Compare( strName, Cur.data.Artist, true ) == 0)
            {
            // Schlüssel gefunden
            Console.WriteLine("===> Found {0}", Cur.data.Artist);
            break;
            }
        
        Prev = Cur;                             // Vorgänger merken
        
        if (string.Compare( strName, Cur.data.Artist , true ) < 0)
            {
            Console.WriteLine("left");
            Cur = Cur.prev;                // gehe zum linken Nachfolger
            dir = Dir.Left;                         // Verzweigungsrichtung merken
            }
        else 
            {
            Console.WriteLine("right");
            Cur = Cur.next;                // gehe zum rechten Nachfolger
            dir = Dir.Right;                         // Verzweigungsrichtung merken
            }
        cnt++;                           // Schrittzähler inkrementieren
        }
      
    if(Cur == null) return -1;             // nicht gefunden

    ///////////////////////////////////// Blatt löschen
    if((Cur.prev == null) && (Cur.next == null)) 
        {
        if(dir == Dir.Right) 
            Prev.next = null;        // Blatt ist rechter Nachfolger
        else
            Prev.prev = null;        // Blatt ist linker Nachfolger
        }
    ///////////////////////////////////// Knoten mit einem Nachfolger. löschen
    if((Cur.prev == null) && (Cur.next != null)) 
        {                                        // Cur hat nur rechten Nachfolger
        if(dir == Dir.Right) 
            Prev.next = Cur.next;
        else
            Prev.prev = Cur.next;
        }
    else if((Cur.prev != null) && (Cur.next == null))
        {
        if(dir == Dir.Right) 
            Prev.next = Cur.prev;    // Cur ist rechter Nachfolger von Prev
        else
            Prev.prev = Cur.prev;    // Cur ist linker Nachfolger von Prev
        }
       
    ///////////////////////////////////// inneren Knoten löschen
    else if((Cur.prev != null) && (Cur.next != null)) 
        {
        PrevSymm = Cur;                            // Symmetrischen Vorgänger s suchen
        CurSymm = Cur.prev;                        // gehe einen Schritt nach links
        while(CurSymm.next != null) 
            {                                      // gehe nach rechts bis zum Ende
            PrevSymm = CurSymm;                    // Vorgänger vs des Sym. Vorgängers
            CurSymm = CurSymm.next;                // Symmetrischer Vorgänger s
            }
            
        if(PrevSymm != Cur) 
            {                                  // Linken Nachfolger von s an Vorgänger
            PrevSymm.next = CurSymm.prev;      // .. des Sym. Nachf. hängen
            CurSymm.prev = Cur.prev;           // s an die Position von k bringen
            }
            
        CurSymm.next = Cur.next;               // s an die Position von k bringen
        if(dir == Dir.Right) 
            Prev.next = CurSymm;      // k ist rechter Nachfolger von v
        else
            Prev.prev = CurSymm;      // k ist linker Nachfolger von v
        }
      return cnt;
      
    }


    } // class
} // namespace
    
    
    
    

syntax highlighted by Code2HTML, v. 0.9.1