context: /***************************************************************************************************************************************
   * Copyright (C) 2001-2012 LearnLift USA																	*
   * Contact: Learnlift USA, 12 Greenway Plaza, Suite 1510, Houston, Texas 77046, support@memorylifter.com					*
   *																								*
   * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License	*
   * as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.			*
   *																								*
   * This library 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 Lesser General Public License for more details.	*
   *																								*
   * You should have received a copy of the GNU Lesser General Public License along with this library; if not,					*
   * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA					*
   ***************************************************************************************************************************************/
  using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Xml.Serialization;
  using MLifter.DAL.DB.PostgreSQL;
  using MLifter.DAL.Interfaces;
  using MLifter.DAL.Interfaces.DB;
  using MLifter.DAL.Tools;
  using MLifter.DAL.XML;
  using System.Text.RegularExpressions;
  
  namespace MLifter.DAL.DB
  {
      /// <summary>
      /// Database implementation of ICardStyle.
      /// </summary>
      /// <remarks>Documented by Dev03, 2009-01-13</remarks>
      class DbCardStyle : ICardStyle
      {
          private IDbCardStyleConnector connector
          {
              get
              {
                  switch (parent.CurrentUser.ConnectionString.Typ)
                  {
                      case DatabaseType.PostgreSQL:
                          return PgSqlCardStyleConnector.GetInstance(parent);
                      case DatabaseType.MsSqlCe:
                          return MLifter.DAL.DB.MsSqlCe.MsSqlCeCardStyleConnector.GetInstance(parent);
                      default:
                          throw new UnsupportedDatabaseTypeException(parent.CurrentUser.ConnectionString.Typ);
                  }
              }
          }
  
          private IDbMediaConnector mediaConnector
          {
              get
              {
                  switch (parent.CurrentUser.ConnectionString.Typ)
                  {
                      case DatabaseType.PostgreSQL:
                          return PgSqlMediaConnector.GetInstance(parent);
                      case DatabaseType.MsSqlCe:
                          return MLifter.DAL.DB.MsSqlCe.MsSqlCeMediaConnector.GetInstance(parent);
                      default:
                          throw new UnsupportedDatabaseTypeException(parent.CurrentUser.ConnectionString.Typ);
                  }
              }
          }
  
          private static XmlSerializer styleSerializer = new XmlSerializer(typeof(XmlCardStyle));
          private XmlCardStyle xmlStyle;
  
          private static Regex cssUrlEntry = new Regex(@"url\((.+)\)");
          private static Regex replaceMediaIds = new Regex(@"MEDIA\[(\d+)\]", RegexOptions.Multiline);
          private static Regex extractSingleMediaId = new Regex(@"^MEDIA\[(\d+)\]$");
          private static string mediaPlaceHolder = "url(MEDIA[{0}])";
  
          private int id;
          /// <summary>
          /// Gets the id.
          /// </summary>
          /// <value>The id.</value>
          /// <remarks>Documented by Dev03, 2009-01-13</remarks>
          public int Id
          {
              get { return id; }
          }
  
          /// <summary>
          /// Initializes a new instance of the <see cref="DbCardStyle"/> class.
          /// </summary>
          /// <param name="id">The id.</param>
          /// <param name="parentClass">The parent class.</param>
          /// <remarks>Documented by Dev03, 2009-01-13</remarks>
          public DbCardStyle(int id, ParentClass parentClass) : this(id, true, parentClass) { }
          /// <summary>
          /// Initializes a new instance of the <see cref="DbCardStyle"/> class.
          /// </summary>
          /// <param name="id">The id.</param>
          /// <param name="checkId">if set to <c>true</c> [check id].</param>
          /// <param name="parentClass">The parent class.</param>
          /// <remarks>Documented by Dev03, 2009-01-13</remarks>
          public DbCardStyle(int id, bool checkId, ParentClass parentClass)
          {
              parent = parentClass;
  
              if (checkId)
                  connector.CheckId(id);
  
              this.id = id;
              String XmlValue = connector.GetCardStyle(id);
  
              if ((XmlValue != null) && (XmlValue.Length > 0))
              {
                  try
                  {
                      xmlStyle = (XmlCardStyle)styleSerializer.Deserialize(new StringReader(XmlValue));
                  }
                  catch
                  {
                      Debug.WriteLine("Failed to deserialize card style!");
                      xmlStyle = new XmlCardStyle(parentClass);
                  }
              }
              else
              {
                  xmlStyle = new XmlCardStyle(parentClass);
              }
          }
  
          /// <summary>
          /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see> as a CSS-Style.
          /// </summary>
          /// <returns>
          /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"> as a CSS-Style</see>.
          /// </returns>
          /// <remarks>Documented by Dev05, 2007-10-30</remarks>
          public override string ToString()
          {
              string cssString = xmlStyle.Question.ToString();
              cssString += xmlStyle.QuestionExample.ToString();
              cssString += xmlStyle.Answer.ToString();
              cssString += xmlStyle.AnswerExample.ToString();
              cssString += xmlStyle.AnswerCorrect.ToString();
              cssString += xmlStyle.AnswerWrong.ToString();
  
              return ReplaceMediaIds(cssString);
          }
  
          /// <summary>
          /// Returns the CSS for this style using the given base path for media URIs.
          /// </summary>
          /// <param name="basePath">The base path.</param>
          /// <returns></returns>
          /// <remarks>Documented by Dev03, 2008-02-22</remarks>
          public string ToString(string basePath)
          {
              basePath = null;
              string cssString = xmlStyle.Question.ToString(basePath);
              cssString += xmlStyle.QuestionExample.ToString(basePath);
              cssString += xmlStyle.Answer.ToString(basePath);
              cssString += xmlStyle.AnswerExample.ToString(basePath);
              cssString += xmlStyle.AnswerCorrect.ToString(basePath);
              cssString += xmlStyle.AnswerWrong.ToString(basePath);
  
              return ReplaceMediaIds(cssString);
          }
  
          private string ReplaceMediaIds(string css)
          {
              string correctCss = replaceMediaIds.Replace(css, delegate(Match match)
              {
                  return DbMediaServer.DbMediaServer.Instance(parent).GetMediaURI(Convert.ToInt32(match.Groups[1].Value)).AbsoluteUri;
              });
              return correctCss;
          }
  
          /// <summary>
          /// Flushes to DB.
          /// </summary>
          /// <remarks>Documented by Dev05, 2008-09-29</remarks>
          internal void FlushToDB()
          {
              SaveMediaToDb();
              StringWriter writer = new StringWriter();
              styleSerializer.Serialize(writer, xmlStyle);
              connector.SetCardStyle(id, writer.ToString());
          }
  
          /// <summary>
          /// Scans the css and remaps and saves any media to the database.
          /// </summary>
          /// <remarks>Documented by Dev09, 2009-03-10</remarks>
          private void SaveMediaToDb()
          {
              List<int> mediaIds = connector.GetMediaForCardStyle(Id);
              connector.ClearMediaForCardStyle(Id);
  
              // find url's in styles
              // regex finds "url(...)" and extracts (or replaces) ...
              ITextStyle[] styles = { xmlStyle.Question, xmlStyle.QuestionExample, xmlStyle.Answer, xmlStyle.AnswerExample, xmlStyle.AnswerCorrect, xmlStyle.AnswerWrong };
              foreach (ITextStyle style in styles)
              {
                  string[] keys = new String[style.OtherElements.Keys.Count];
                  style.OtherElements.Keys.CopyTo(keys, 0);
                  foreach (string key in keys)
                  {
  
gt:                     String value = style.OtherElements[key];