-- $Date: 2004/03/04 05:11:31 $
-- $Revision: 1.16 $
-- $Author: jcrocholl $

with Ada.Tags;

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

with Keys.MusicXML; use Keys.MusicXML;
with Times.MusicXML; use Times.MusicXML;
with Clefs.MusicXML; use Clefs.MusicXML;

with Music.MusicXML; use Music.MusicXML;
with Music.Notes.MusicXML; use Music.Notes.MusicXML;
with Music.Directions.MusicXML; use Music.Directions.MusicXML;
with Music.Barlines.MusicXML; use Music.Barlines.MusicXML;

package body Measures.MusicXML is

   -- Write a list of clefs to an XML writer.
   procedure Write_Clefs
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Clef_List)  -- Write these clefs.
   is
      use Clef_Lists;
      Clef : Clef_Access;
   begin
      Reset(This);
      while Next(This) loop
         Clef := Current(This);
         Write_Clef(XML, Clef);
      end loop;
   end Write_Clefs;

   -- Read a list of time signatures from an XML reader.
   procedure Read_Times
     (XML  : access XML_Reader-- Use this XML reader.
      This : access Measure)    -- Add times to this measure.
   is
      use Time_Lists;
      Time   : Time_Access;
      Symbol : Symbol_Enum := Normal;
   begin
      if not End_Of_Tag(XML) then
         Assert_Attribute_Name(XML, "symbol");
         Read_Attribute_Value(XML);
         Symbol := To_Symbol_Enum(Get_Token(XML));
      end if;
      Exit_Tag(XML);

      while Descend(XML) loop
         if Context_Is(XML, "beats") then
            Exit_Tag(XML);
            Time := Read_Beats(XML, Symbol);
            Add_Time(This, Time);
            Symbol := Normal;
         else
            XML_Expect_Error(XML, "/time", "beats");
         end if;
      end loop;
      Exit_Tag(XML);
   end Read_Times;

   -- Write a list of time signatures to an XML writer.
   procedure Write_Times
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Measure)    -- Write times of this measure.
   is
      use Time_Lists;
      Time : Time_Access;
   begin
      Start_Element(XML, "time");
      Reset(This.Times);
      while Next(This.Times) loop
         Time := Current(This.Times);
         Write_Beats(XML, Time);
      end loop;
      Close_Element(XML, "time");
   end Write_Times;

   procedure Read_Attributes
     (XML  : access XML_Reader-- Use this XML reader.
      This : access Measure) is -- Store attributes in this measure.
   begin
      Exit_Tag(XML);
      while Descend(XML) loop
         if not Context_Is(XML, "clef")
           and not Context_Is(XML, "time")
         then
            Exit_Tag(XML);
         end if;

         if Found(XML, "divisions") then
            Set_Divisions(This, To_Number(Read_Data(XML)));
         elsif Found(XML, "key") then
            Set_Key(This, Read_Key(XML));
         elsif Found(XML, "time") then
            Read_Times(XML, This);
         elsif Found(XML, "staves") then
            Set_Staves(This, To_Number(Read_Data(XML)));
         elsif Found(XML, "clef") then
            Add_Clef(This, Read_Clef(XML));
         else
            XML_Expect_Error(XML, "/attributes",
              "divisions" / "key" / "time" / "clef");
         end if;

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

   procedure Write_Attributes
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Measure)    -- Store attributes in this measure.
   is
      use Clef_Lists;
      use Time_Lists;
   begin
      if Get_Divisions(This) = 1
        and Get_Key(This) = null
        and Count(Get_Times(This)) = 0
        and Get_Staves(This) = 0
        and Empty(Get_Clefs(This))
      then
         return;
      end if;

      Start_Element(XML, "attributes");

      if Get_Divisions(This) /= 1 then
         Write_Element(XML, "divisions", To_String(Get_Divisions(This)));
      end if;

      if Get_Key(This) /= null then Write_Key(XML, Get_Key(This)); end if;
      Write_Times(XML, This);

      if Get_Staves(This) /= 0 then
         Write_Element(XML, "staves", To_String(Get_Staves(This)));
      end if;

      if not Empty(Get_Clefs(This)) then
         Write_Clefs(XML, Get_Clefs(This));
      end if;

      Close_Element(XML, "attributes");
   end Write_Attributes;

   -- Read some notes from an XML reader.
   procedure Read_Musics
     (XML  : access XML_Reader-- Use this XML reader.
      This : access Measure) is -- Add notes to this measure.
   begin
      while Descend(XML) loop
         if Found(XML, "attributes") then
            Read_Attributes(XML, This);
         else
            Add_Music(This, Read_Music(XML, "/measure" / "attributes"));
         end if;
      end loop;

      Exit_Tag(XML);
   end Read_Musics;

   -- Write a list of music data to an XML writer.
   procedure Write_Musics
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Music_List-- Write these musics.
   is
      use Music_Lists;
      Music_Data : Music_Data_Access;
   begin
      Reset(This);
      while Next(This) loop
         Music_Data := Current(This);
         Write_Music(XML, Music_Data);
      end loop;
   end Write_Musics;

   -- Read measure data from an XML reader.
   function Read_Measure
     (XML : access XML_Reader-- Use this XML reader.
     return Measure_Access     -- The newly created measure.
   is
      Result : Measure_Access;
   begin
      Assert_Attribute_Name(XML, "number");
      Read_Attribute_Value(XML);
      Result := Create(To_Number(Get_Token(XML)));
      Exit_Tag(XML);
      Read_Musics(XML, Result);
      return Result;
   end Read_Measure;

   -- Write measure data to an XML writer.
   procedure Write_Measure
     (XML  : access XML_Writer-- Use this XML writer.
      This : access Measure)    -- Write this measure.
   is
   begin
      Start_Element(XML, "measure", "number", To_String(Get_Number(This)));
      Write_Attributes(XML, This);
      Write_Musics(XML, Get_Musics(This));
      Close_Element(XML, "measure");
   end Write_Measure;

end Measures.MusicXML;