-- $Date: 2004/03/08 11:08:13 $
-- $Revision: 1.9 $
-- $Author: jcrocholl $

with Readers; use Readers;
with Token_Readers; use Token_Readers;
with Integer_Strings; use Integer_Strings;
with Enum_Strings; use Enum_Strings;

with Pitches.MusicXML; use Pitches.MusicXML;
with Lyrics.MusicXML; use Lyrics.MusicXML;

with Notations.MusicXML; use Notations.MusicXML;
with Notations.Slurs.MusicXML; use Notations.Slurs.MusicXML;
with Notations.Articulations.MusicXML; use Notations.Articulations.MusicXML;

package body Music.Notes.MusicXML is

   procedure Read_Beam
     (XML  : access XML_Reader-- Use this XML reader.
      This : access Note)       -- Add beam to this note.
   is
      Index      : Positive;
      Beam_State : Beam_State_Enum;
   begin
      Assert_Attribute_Name(XML, "number");
      Read_Attribute_Value(XML);
      Index := To_Number(Get_Token(XML));
      Exit_Tag(XML);
      Beam_State := To_Beam_State_Enum(Read_Data(XML));
      Set_Beam_State(This, Index, Beam_State);
   end Read_Beam;

   procedure Write_Beams
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Note) is    -- Write beam information for this note.
   begin
      for Index in Beam_Range loop
         if Get_Beam_State(This, Index) /= None then
            Write_Element(XML, "beam", "number", To_String(Index),
              To_XML(Get_Beam_State(This, Index)'Img));
         end if;
      end loop;
   end Write_Beams;

   procedure Read_Articulations
     (XML  : access XML_Reader-- Use this XML reader.
      This : access Note) is    -- Add articulation notations to this note.
   begin
      while Descend(XML) loop
         Add_Notation(This, Read_Articulation(XML));
      end loop;
      Exit_Tag(XML);
   end Read_Articulations;

   procedure Read_Notations
     (XML  : access XML_Reader-- Use this XML reader.
      This : access Note) is    -- Add notations to this note.
   begin
      while Descend(XML) loop
         if Found(XML, "articulations") then
            Exit_Tag(XML);
            Read_Articulations(XML, This);
         else
            Add_Notation(This, Read_Notation(XML));
         end if;
      end loop;
      Exit_Tag(XML);
   end Read_Notations;

   procedure Write_Notations
     (XML  : access XML_Writer;    -- Use this XML writer.
      This : access Notation_List-- Write these notations.
   is
      use Notation_Lists;
      Notation : Notations.Notation_Access;
      Arti     : Boolean := False; -- Inside articulations?
   begin
      Start_Element(XML, "notations");
      Reset(This);
      while Next(This) loop
         Notation := Current(This);
         Write_Notation(XML, Notation, Arti);
      end loop;

      if Arti then
         Close_Element(XML, "articulations");
      end if;

      Close_Element(XML, "notations");
   end Write_Notations;

   -- Read note data from an XML reader.
   function Read_Note
     (XML : access XML_Reader-- Use this XML reader.
     return Note_Access        -- The newly created note.
   is
      Result : Note_Access := Create;
   begin
      if not End_Of_Tag(XML) then
         Assert_Attribute_Name(XML, "filled");
         Read_Attribute_Value(XML);
         Set_Filled(Result, To_Filled_Enum(Get_Token(XML)));
      end if;
      Exit_Tag(XML);

      while Descend(XML) loop
         if not Context_Is(XML, "lyric")
           and not Context_Is(XML, "beam")
         then
            Exit_Tag(XML);
         end if;

         if Found(XML, "grace") then Set_Grace(Result, True);
         elsif Found(XML, "chord") then Set_Chord(Result, True);
         elsif Found(XML, "pitch") then Set_Pitch(Result, Read_Pitch(XML));
         elsif Found(XML, "duration") then Set_Duration(Result, To_Number(Read_Data(XML)));
         elsif Found(XML, "voice") then Set_Voice(Result, To_Number(Read_Data(XML)));
         elsif Found(XML, "type") then Set_Note_Type(Result, To_Note_Type_Enum(Read_Data(XML)));
         elsif Found(XML, "dot") then Add_Dot(Result);
         elsif Found(XML, "stem") then Set_Stem(Result, To_Stem_Enum(Read_Data(XML)));
         elsif Found(XML, "staff") then Set_Staff(Result, To_Number(Read_Data(XML)));
         elsif Found(XML, "beam") then Read_Beam(XML, Result);
         elsif Found(XML, "notations") then Read_Notations(XML, Result);
         elsif Found(XML, "lyric") then Set_Lyric(Result, Read_Lyric(XML));
         else XML_Expect_Error(XML, "/note",
            "grace" / "chord" / "pitch" / "duration" / "voice" / "type" / "dot" /
              "stem" / "staff" / "beam" / "notations" / "lyric");
         end if;

         if not Context_Is(XML, "note") then
            Exit_Element(XML);
         end if;
      end loop;
      Exit_Tag(XML);

      return Result;
   end Read_Note;

   -- Write note data to an XML writer.
   procedure Write_Note
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Note) is    -- Write this note.
   begin
      Start_Element(XML, "note");

      if Get_Grace(This) then Write_Element(XML, "grace"); end if;
      if Get_Chord(This) then Write_Element(XML, "chord"); end if;

      Write_Pitch(XML, Get_Pitch(This));

      if Get_Duration(This) /= 0 then
         Write_Element(XML, "duration", To_String(Get_Duration(This)));
      end if;

      if Get_Voice(This) /= 0 then
         Write_Element(XML, "voice", To_String(Get_Voice(This)));
      end if;

      Write_Element(XML, "type", To_XML(Get_Note_Type(This)'Img));

      for Index in 1 .. Get_Dots(This) loop
         Write_Element(XML, "dot");
      end loop;

      if Get_Stem(This) /= Auto then
         Write_Element(XML, "stem", To_XML(Get_Stem(This)'Img));
      end if;

      if Get_Staff(This) /= 0 then
         Write_Element(XML, "staff", To_String(Get_Staff(This)));
      end if;

      Write_Beams(XML, This);

      if not Notation_Lists.Empty(Get_Notations(This)) then
         Write_Notations(XML, Get_Notations(This));
      end if;

      if Get_Lyric(This) /= null then
         Write_Lyric(XML, Get_Lyric(This));
      end if;

      Close_Element(XML, "note");
   end Write_Note;

end Music.Notes.MusicXML;