/// <summary>
        /// Дабавляет файл, возвращает добавленные в базу данных элементы
        /// </summary>
        /// <param name="file"></param>
        /// <param name="collectionId"></param>
        /// <returns></returns>
        public static IEnumerable <XElement> AddFile(this Cassette cassette, FileInfo file, string collectionId)
        {
            List <XElement> addedElements = new List <XElement>(); // string smallImageFullName = null;
            string          fname         = file.FullName;
            XElement        doc           = null;
            // Первая задача - выделить тождественный документ, он помещается в doc
            // Проверка на существование документа в архиве, удовлетворяющего условиям: размер совпадает,
            // расширитель совпадает и байтовая последовательность также совпадает
            string fileSize = file.Length.ToString();
            string fileExt  = Path.GetExtension(fname).ToLower();//fname.Substring(fname.LastIndexOf('.')).ToLower(); // расширение вместе с точкой

            doc =
                cassette.db.Elements()
                .FirstOrDefault(
                    (XElement e) =>
            {
                XElement iisstore = e.Element(ONames.TagIisstore);
                if (iisstore == null)
                {
                    return(false);
                }
                XAttribute on = iisstore.Attribute(ONames.AttOriginalname);
                XAttribute sz = iisstore.Attribute(ONames.AttSize);
                if (on == null || sz == null)
                {
                    return(false);
                }
                string uri = iisstore.Attribute(ONames.AttUri).Value;
                if (!on.Value.ToLower().EndsWith(fileExt) || sz.Value != fileSize)
                {
                    return(false);
                }
                if (File.ReadAllBytes(fname)
                    .SequenceEqual(
                        File.ReadAllBytes(cassette.Dir.FullName + "/" + cassette.GetOriginalDocumentPath(uri))))
                {
                    return(true);
                }
                return(false);
            });
            bool docIsNew = (doc == null);

            if (docIsNew)
            {
                // Включение файла в архив
                string pure_fname = fname.Split(Cassette.slashes).Last();
                //int p = pure_fname.LastIndexOf('.');
                string ext = Path.GetExtension(pure_fname).ToLower();//(p != -1 ? pure_fname.Substring(p).ToLower() : "");
                // копируем оригинал под имеющимся расширением
                var filepath = cassette.Dir.FullName + "/originals/" + cassette._folderNumber + "/" + cassette._documentNumber + ext;
                try
                {
                    File.Copy(fname, filepath);
                }
                catch (Exception exc)
                {
                    LOG.WriteLine("ошибка добавления документа, не послучилось скопировать  в " + filepath +
                                  Environment.NewLine +
                                  exc.Message +
                                  Environment.NewLine +
                                  exc.StackTrace
                                  );
                    return(null);
                } // Надо бы эту нештатную ситуацию зафиксировать в каком-нибудь логе

                // Создаем запись и привязываем ее к коллекции
                DocType triple       = Cassette.docTypes.Where(doct => doct.ext == ext || doct.ext == "unknown").First();
                var     ex           = triple.ext;
                var     documenttype = triple.content_type;
                var     docTag       = triple.tag;

                XName docId    = XName.Get(cassette.Name + "_" + cassette._folderNumber + "_" + cassette._documentNumber);
                var   iisstore = new XElement(ONames.TagIisstore,
                                              new XAttribute(ONames.AttUri, "iiss://" + cassette.Name + "@iis.nsk.su/0001/" + cassette._folderNumber + "/" + cassette._documentNumber),
                                              new XAttribute(ONames.AttOriginalname, fname),
                                              new XAttribute(ONames.AttSize, file.Length.ToString()),
                                              new XAttribute(ONames.AttDocumenttype, documenttype),
                                              new XAttribute(ONames.AttDocumentcreation, file.CreationTimeUtc.ToString("s")),
                                              new XAttribute(ONames.AttDocumentfirstuploaded, System.DateTime.Now.ToString("s")),
                                              new XAttribute(ONames.AttDocumentmodification, file.LastWriteTimeUtc.ToString("s")),
                                              new XAttribute(ONames.AttChecksum, "qwerty"));
                //string documentname = cassette.Name + " " + cassette._folderNumber + " " + cassette._documentNumber;
                //TODO: поменял концепцию формирования имени документа
                int    lastpoint      = fname.LastIndexOf('.');
                int    afterlastslash = Math.Max(fname.LastIndexOf('/'), fname.LastIndexOf('\\')) + 1;
                string documentname   = cassette.DocNamePrefix +
                                        fname.Substring(afterlastslash, lastpoint > afterlastslash ? lastpoint - afterlastslash : fname.Length - afterlastslash);
                doc = new XElement(docTag,
                                   new XAttribute(ONames.rdfabout, docId),
                                   new XElement(ONames.TagName, documentname),
                                   new XElement(ONames.TagComment, fname),
                                   iisstore);
                // Дополнительная обработка для фотографий
                if (docTag == ONames.TagPhotodoc)
                {
                    // Делаем разные копии
                    Uri _source = cassette.MakePhotoPreviews(iisstore, "smn");
                    if (_source != null)
                    {
                        try
                        {
                            // Берем exif-данные
                            Exif.ExifMetadata emeta = new Exif.ExifMetadata(_source);
                            var dit = emeta.DateImageTaken;
                            if (dit.HasValue)
                            {
                                DateTime dt = dit.Value;
                                doc.Add(
                                    new XElement(ONames.TagFromdate, dt.ToString("s")));
                            }
                        }
                        catch (Exception exep) { Fogid.Cassettes.LOG.WriteLine(exep.Message + " Не удалось зафиксировать Exif информацию по документу " + iisstore.ToString()); }
                    }
                }
                // Дополнительная обработка для видео
                if (docTag == ONames.TagVideo)
                {
                    int o_width  = 640; // Это значения "от фонаря"
                    int o_height = 480;
                    // Сначала, почитаем метаинформацию. Используется программа MediaInfo
                    string output = "";
                    try
                    {
                        var proc = new System.Diagnostics.Process();
                        // Redirect the output stream of the child process.
                        proc.StartInfo.UseShellExecute        = false;
                        proc.StartInfo.RedirectStandardOutput = true;
                        proc.StartInfo.FileName  = App_Bin_Path + "MediaInfo.exe";
                        proc.StartInfo.Arguments = " --Output=XML " +
                                                   cassette.Dir.FullName + "/originals/" + cassette._folderNumber + "/" + cassette._documentNumber + ext;
                        proc.Start();
                        // Do not wait for the child process to exit before
                        // reading to the end of its redirected stream.
                        // proc.WaitForExit();
                        // Read the output stream first and then wait.
                        output = proc.StandardOutput.ReadToEnd();
                        proc.WaitForExit();
                        var    xoutput    = XElement.Parse(output).Element("File");
                        string o_width_s  = xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Width").Value;
                        string o_height_s = xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Height").Value;
                        o_width  = Int32.Parse(new string(o_width_s.Where(c => c >= '0' && c <= '9').ToArray()));
                        o_height = Int32.Parse(new string(o_height_s.Where(c => c >= '0' && c <= '9').ToArray()));
                        // Display_aspect_ratio
                        string o_aspect_s = xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Display_aspect_ratio").Value;
                        iisstore.Add(
                            new XAttribute("width", "" + o_width),
                            new XAttribute("height", "" + o_height),
                            new XAttribute("duration",
                                           xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Duration").Value),
                            new XAttribute("framerate",
                                           xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Frame_rate").Value),
                            o_aspect_s == "4:3" || o_aspect_s == "16:9" ?
                            new XAttribute("aspect", o_aspect_s) : null,
                            null);
                    }
                    catch (Exception exc)
                    {
                        LOG.WriteLine(" ошибка добавления документа, не получилось обработать видео " + output +
                                      Environment.NewLine +
                                      exc.Message +
                                      Environment.NewLine +
                                      exc.StackTrace
                                      );
                    }

                    string   sz                = cassette.GetPreviewParameter(iisstore, "medium", "framesize");
                    string[] w_h               = sz.Split(new char[] { 'x' });
                    int      m_width           = Int32.Parse(w_h[0]);
                    int      m_height          = Int32.Parse(w_h[1]);
                    int      m_width_corrected = m_height * o_width / o_height;
                    // Если кадр меньше запланированного, оставляем "родной" размер
                    string output_size = m_height < o_height ? m_width_corrected + "x" + m_height : o_width + "x" + o_height;
                    // Зафиксируем размер в iisstore
                    if (output_size != cassette.finfo.Element("video").Element("medium").Attribute("framesize").Value)
                    {
                        var framesize_att = iisstore.Attribute("video.medium.framesize");
                        if (framesize_att == null)
                        {
                            iisstore.Add(new XAttribute("video.medium.framesize", "" + output_size));
                        }
                        else
                        {
                            framesize_att.Value = "" + output_size;
                        }
                    }
                    // Сформируем команду на вычисление превьюшки
                    cassette.MakeVideoPreview(iisstore);
                    // Зафиксируем дату съемки по LastWriteTime
                    DateTime dt =
                        cassette.Dir.GetFiles("originals/" + cassette._folderNumber + "/" + cassette._documentNumber + ext)[0].LastWriteTime;
                    doc.Add(new XElement(ONames.TagFromdate, dt.ToString("s")));
                }
                // дополнительная обработка аудио
                if (docTag == ONames.TagAudio)
                {
                    cassette.MakeAudioPreview(iisstore);
                }

                cassette.IncrementDocumentNumber();
                addedElements.Add(doc);
                cassette.db.Add(doc);
                // попытка добавить принадлежность к архиву
                XElement archMember = cassette.CreateArchiveMember(docId.ToString());
                if (archMember != null)
                {
                    addedElements.Add(archMember);
                    cassette.db.Add(archMember);
                }
            }
            else
            {
                doc = XElement.Parse(doc.ToString()); doc.Add(new XAttribute("itIsCopy", "true")); addedElements.Add(doc);
            }
            string dId = doc.Attribute(ONames.rdfabout).Value;
            // Проверим наличие связи
            bool membershipExists =
                (!docIsNew) &&

                //var collmem =
                cassette.db.Elements(ONames.TagCollectionmember)
                .Any(cm =>
                     cm.Element(ONames.TagCollectionitem).Attribute(ONames.rdfresource).Value == dId &&
                     cm.Element(ONames.TagIncollection).Attribute(ONames.rdfresource).Value == collectionId);

            //  if (collmem != null) membershipExists = true;

            // А теперь, наконец, добавим членство в коллекции
            if (!membershipExists)
            {
                XElement collectionmember =
                    new XElement(ONames.TagCollectionmember,
                                 new XAttribute(ONames.rdfabout, cassette.Name + "_" + collectionId + "_" + dId),
                                 new XElement(ONames.TagIncollection, new XAttribute(ONames.rdfresource, collectionId)),
                                 new XElement(ONames.TagCollectionitem, new XAttribute(ONames.rdfresource, dId)));
                addedElements.Add(collectionmember);
                cassette.db.Add(collectionmember);
            }
            return(addedElements);
        }
        /// <summary>
        /// Дабавляет файл, возвращает добавленные в базу данных элементы
        /// </summary>
        /// <param name="file"></param>
        /// <param name="collectionId"></param>
        /// <returns></returns>
        public static IEnumerable<XElement> AddFile(this Cassette cassette, FileInfo file, string collectionId)
        {
            List<XElement> addedElements = new List<XElement>(); // string smallImageFullName = null;
            string fname = file.FullName;
            XElement doc = null;
            // Первая задача - выделить тождественный документ, он помещается в doc
            // Проверка на существование документа в архиве, удовлетворяющего условиям: размер совпадает,
            // расширитель совпадает и байтовая последовательность также совпадает
            string fileSize = file.Length.ToString();
            string fileExt = Path.GetExtension(fname).ToLower();//fname.Substring(fname.LastIndexOf('.')).ToLower(); // расширение вместе с точкой
            doc =
                cassette.db.Elements()
                    .FirstOrDefault(
                        (XElement e) =>
                        {
                            XElement iisstore = e.Element(ONames.TagIisstore);
                            if(iisstore == null) return false;
                            XAttribute on = iisstore.Attribute(ONames.AttOriginalname);
                            XAttribute sz = iisstore.Attribute(ONames.AttSize);
                            if(on == null || sz == null) return false;
                            string uri = iisstore.Attribute(ONames.AttUri).Value;
                            if(!on.Value.ToLower().EndsWith(fileExt) || sz.Value != fileSize) return false;
                            if(File.ReadAllBytes(fname)
                                .SequenceEqual(
                                    File.ReadAllBytes(cassette.Dir.FullName + "/" + cassette.GetOriginalDocumentPath(uri)))) return true;
                            return false;
                        });
            bool docIsNew = (doc == null);
            if(docIsNew)
            {
                // Включение файла в архив
                string pure_fname = fname.Split(Cassette.slashes).Last();
                //int p = pure_fname.LastIndexOf('.');
                string ext = Path.GetExtension(pure_fname).ToLower();//(p != -1 ? pure_fname.Substring(p).ToLower() : "");
                // копируем оригинал под имеющимся расширением
                var filepath = cassette.Dir.FullName + "/originals/" + cassette._folderNumber + "/" + cassette._documentNumber + ext;
                try
                {
                    File.Copy(fname, filepath);
                }
                catch(Exception exc)
                {
                    LOG.WriteLine("ошибка добавления документа, не послучилось скопировать  в " + filepath+
                    Environment.NewLine+
                    exc.Message+
                    Environment.NewLine+
                    exc.StackTrace
                        );
                    return null;
                } // Надо бы эту нештатную ситуацию зафиксировать в каком-нибудь логе

                // Создаем запись и привязываем ее к коллекции
                DocType triple = Cassette.docTypes.Where(doct => doct.ext == ext || doct.ext == "unknown").First();
                var ex = triple.ext;
                var documenttype = triple.content_type;
                var docTag = triple.tag;

                XName docId = XName.Get(cassette.Name + "_" + cassette._folderNumber + "_" + cassette._documentNumber);
                var iisstore = new XElement(ONames.TagIisstore,
                            new XAttribute(ONames.AttUri, "iiss://" + cassette.Name + "@iis.nsk.su/0001/" + cassette._folderNumber + "/" + cassette._documentNumber),
                            new XAttribute(ONames.AttOriginalname, fname),
                            new XAttribute(ONames.AttSize, file.Length.ToString()),
                            new XAttribute(ONames.AttDocumenttype, documenttype),
                            new XAttribute(ONames.AttDocumentcreation, file.CreationTimeUtc.ToString("s")),
                            new XAttribute(ONames.AttDocumentfirstuploaded, System.DateTime.Now.ToString("s")),
                            new XAttribute(ONames.AttDocumentmodification, file.LastWriteTimeUtc.ToString("s")),
                            new XAttribute(ONames.AttChecksum, "qwerty"));
                //string documentname = cassette.Name + " " + cassette._folderNumber + " " + cassette._documentNumber;
                //TODO: поменял концепцию формирования имени документа
                int lastpoint = fname.LastIndexOf('.');
                int afterlastslash = Math.Max(fname.LastIndexOf('/'), fname.LastIndexOf('\\')) + 1;
                string documentname = cassette.DocNamePrefix +
                    fname.Substring(afterlastslash, lastpoint > afterlastslash ? lastpoint - afterlastslash : fname.Length - afterlastslash);
                doc = new XElement(docTag,
                        new XAttribute(ONames.rdfabout, docId),
                        new XElement(ONames.TagName, documentname),
                        new XElement(ONames.TagComment, fname),
                        iisstore);
                // Дополнительная обработка для фотографий
                if(docTag == ONames.TagPhotodoc)
                {
                    // Делаем разные копии
                    Uri _source = cassette.MakePhotoPreviews(iisstore, "smn");
                    if(_source != null)
                        try
                        {
                            // Берем exif-данные
                            Exif.ExifMetadata emeta = new Exif.ExifMetadata(_source);
                            var dit = emeta.DateImageTaken;
                            if(dit.HasValue)
                            {
                                DateTime dt = dit.Value;
                                doc.Add(
                                    new XElement(ONames.TagFromdate, dt.ToString("s")));
                            }
                        }
                        catch(Exception exep) { Fogid.Cassettes.LOG.WriteLine(exep.Message +  " Не удалось зафиксировать Exif информацию по документу " + iisstore.ToString()); }
                }
                // Дополнительная обработка для видео
                if(docTag == ONames.TagVideo)
                {
                    int o_width = 640; // Это значения "от фонаря"
                    int o_height = 480;
                    // Сначала, почитаем метаинформацию. Используется программа MediaInfo
                    string output="";
                    try
                    {
                        var proc = new System.Diagnostics.Process();
                        // Redirect the output stream of the child process.
                        proc.StartInfo.UseShellExecute = false;
                        proc.StartInfo.RedirectStandardOutput = true;
                        proc.StartInfo.FileName = App_Bin_Path + "MediaInfo.exe";
                        proc.StartInfo.Arguments = " --Output=XML " +
                            cassette.Dir.FullName + "/originals/"+ cassette._folderNumber + "/" + cassette._documentNumber + ext;
                        proc.Start();
                        // Do not wait for the child process to exit before
                        // reading to the end of its redirected stream.
                        // proc.WaitForExit();
                        // Read the output stream first and then wait.
                        output = proc.StandardOutput.ReadToEnd();
                        proc.WaitForExit();
                        var xoutput = XElement.Parse(output).Element("File");
                        string o_width_s = xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Width").Value;
                        string o_height_s = xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Height").Value;
                        o_width = Int32.Parse(new string(o_width_s.Where(c => c >= '0' && c <= '9').ToArray()));
                        o_height = Int32.Parse(new string(o_height_s.Where(c => c >= '0' && c <= '9').ToArray()));
                        // Display_aspect_ratio
                        string o_aspect_s = xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Display_aspect_ratio").Value;
                        iisstore.Add(
                            new XAttribute("width", "" + o_width),
                            new XAttribute("height", "" + o_height),
                            new XAttribute("duration",
                                xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Duration").Value),
                            new XAttribute("framerate",
                                xoutput.Elements("track").First(tr => tr.Attribute("type").Value == "Video").Element("Frame_rate").Value),
                            o_aspect_s == "4:3" || o_aspect_s == "16:9" ?
                            new XAttribute("aspect", o_aspect_s) : null,
                            null);
                    }
                    catch(Exception exc)
                    {
                        LOG.WriteLine(" ошибка добавления документа, не получилось обработать видео " + output +
                        Environment.NewLine +
                        exc.Message +
                        Environment.NewLine +
                        exc.StackTrace
                        );
                    }

                    string sz = cassette.GetPreviewParameter(iisstore, "medium", "framesize");
                    string[] w_h = sz.Split(new char[] { 'x' });
                    int m_width = Int32.Parse(w_h[0]);
                    int m_height = Int32.Parse(w_h[1]);
                    int m_width_corrected = m_height * o_width / o_height;
                    // Если кадр меньше запланированного, оставляем "родной" размер
                    string output_size = m_height < o_height ? m_width_corrected + "x" + m_height : o_width + "x" + o_height;
                    // Зафиксируем размер в iisstore
                    if(output_size != cassette.finfo.Element("video").Element("medium").Attribute("framesize").Value)
                    {
                        var framesize_att = iisstore.Attribute("video.medium.framesize");
                        if(framesize_att == null)
                        {
                            iisstore.Add(new XAttribute("video.medium.framesize", "" + output_size));
                        }
                        else
                        {
                            framesize_att.Value = "" + output_size;
                        }
                    }
                    // Сформируем команду на вычисление превьюшки
                    cassette.MakeVideoPreview(iisstore);
                    // Зафиксируем дату съемки по LastWriteTime
                    DateTime dt =
                        cassette.Dir.GetFiles("originals/" + cassette._folderNumber + "/" + cassette._documentNumber + ext)[0].LastWriteTime;
                    doc.Add(new XElement(ONames.TagFromdate, dt.ToString("s")));
                }
                // дополнительная обработка аудио
                if (docTag == ONames.TagAudio)
                {
                    cassette.MakeAudioPreview(iisstore);
                }

                cassette.IncrementDocumentNumber();
                addedElements.Add(doc);
                cassette.db.Add(doc);
                // попытка добавить принадлежность к архиву
                XElement archMember = cassette.CreateArchiveMember(docId.ToString());
                if(archMember != null)
                {
                    addedElements.Add(archMember);
                    cassette.db.Add(archMember);
                }
            }
            else { doc = XElement.Parse(doc.ToString()); doc.Add(new XAttribute("itIsCopy", "true")); addedElements.Add(doc); }
            string dId = doc.Attribute(ONames.rdfabout).Value;
            // Проверим наличие связи
            bool membershipExists =
            (!docIsNew) &&

                //var collmem =
                    cassette.db.Elements(ONames.TagCollectionmember)
                    .Any(cm =>
                        cm.Element(ONames.TagCollectionitem).Attribute(ONames.rdfresource).Value == dId &&
                        cm.Element(ONames.TagIncollection).Attribute(ONames.rdfresource).Value == collectionId);
            //  if (collmem != null) membershipExists = true;

            // А теперь, наконец, добавим членство в коллекции
            if(!membershipExists)
            {
                XElement collectionmember =
                    new XElement(ONames.TagCollectionmember,
                        new XAttribute(ONames.rdfabout, cassette.Name + "_" + collectionId + "_" + dId),
                        new XElement(ONames.TagIncollection, new XAttribute(ONames.rdfresource, collectionId)),
                        new XElement(ONames.TagCollectionitem, new XAttribute(ONames.rdfresource, dId)));
                addedElements.Add(collectionmember);
                cassette.db.Add(collectionmember);
            }
            return addedElements;
        }