public IList <ScheduleEntryBaseDTO> SaveScheduleEntryRange(SaveScheduleEntryRangeParam saveScheduleEntryRangeParam)
        {
            DateTime startDate = saveScheduleEntryRangeParam.StartDay;
            DateTime endDate   = saveScheduleEntryRangeParam.EndDay.AddDays(1);

            Log.WriteWarning("SaveScheduleEntriesRange:Username={0},Start={1},End={2}", SecurityInfo.SessionData.Profile.UserName, saveScheduleEntryRangeParam.StartDay, saveScheduleEntryRangeParam.EndDay);

            if (!SecurityInfo.Licence.IsInstructor)
            {
                throw new LicenceException("This feature is allowed for Instructor account");
            }

            if (saveScheduleEntryRangeParam.Entries.Where(x => x.StartTime < startDate).Count() > 0 || saveScheduleEntryRangeParam.Entries.Where(x => x.EndTime > endDate).Count() > 0)
            {
                throw new ArgumentOutOfRangeException("Entries are out of range StartDay and EndDay");
            }



            //determine if we should copy instead of save
            bool copy = saveScheduleEntryRangeParam.CopyStart != null && saveScheduleEntryRangeParam.CopyEnd != null;

            var newDb = saveScheduleEntryRangeParam.Entries.Map <IList <ScheduleEntryBase> >();

            using (var trans = Session.BeginSaveTransaction())
            {
                var dbProfile = Session.Load <Profile>(SecurityInfo.SessionData.Profile.GlobalId);
                IList <ScheduleEntryBase> itemsToSave;
                if (copy)
                {
                    //if((saveScheduleEntryRangeParam.CopyStart.Value-saveScheduleEntryRangeParam.StartDay).TotalDays<7 ||
                    //    (saveScheduleEntryRangeParam.CopyEnd.Value - saveScheduleEntryRangeParam.EndDay).TotalDays < 7)
                    //{
                    //    throw new ArgumentException("Copy start and end range must be at least one week after source range");
                    //}
                    //var count =Session.QueryOver<ScheduleEntry>().Where(x =>x.StartTime >= saveScheduleEntryRangeParam.CopyStart.Value && x.EndTime <= saveScheduleEntryRangeParam.CopyEnd.Value && x.Profile == dbProfile).RowCount();
                    //if (count>0)
                    //{
                    //    throw new AlreadyOccupiedException("Destination days are occupied already");
                    //}
                    var count = Session.QueryOver <ScheduleEntry>().Where(x => x.StartTime >= saveScheduleEntryRangeParam.CopyStart.Value && x.EndTime <= saveScheduleEntryRangeParam.CopyEnd.Value && x.Profile == dbProfile).List();
                    if (count.Count > 0)
                    {
                        throw new AlreadyOccupiedException("Destination days are occupied already");
                    }
                    itemsToSave = newDb;
                }
                else
                {
                    var db       = Session.QueryOver <ScheduleEntryBase>().Where(x => x.StartTime >= startDate && x.EndTime < endDate && x.Profile == dbProfile).List();
                    var comparer = new CollectionComparer <ScheduleEntryBase>(newDb, db);
                    foreach (var entry in comparer.RemovedItems)
                    {
                        if (entry.IsLocked)
                        {
                            throw new DeleteConstraintException("Cannot delete schedule entry");
                        }
                        Session.Delete(entry);
                    }
                    itemsToSave = comparer.GetForSaveItems();
                }

                for (int index = 0; index < itemsToSave.Count; index++)
                {
                    var entry = itemsToSave[index];
                    ScheduleEntryBase dbOldEntry = null;
                    if (entry.GlobalId != Guid.Empty)
                    {
                        dbOldEntry         = Session.QueryOver <ScheduleEntryBase>().Fetch(x => x.Reminder).Eager.Where(x => x.GlobalId == entry.GlobalId).SingleOrDefault();
                        entry.Reservations = dbOldEntry.Reservations;
                        entry.Reminder     = dbOldEntry.Reminder;
                        if (!copy && entry.IsLocked)
                        {//if we are in saving mode and this entry is locked then skip to the next one
                            itemsToSave[index] = dbOldEntry;
                            continue;
                        }
                    }
                    if (dbOldEntry == null)
                    {
                        entry.Profile = dbProfile;
                        dbOldEntry    = entry;
                    }


                    var scheduleEntry = entry as ScheduleEntry;

                    if (dbOldEntry.Profile != dbProfile)
                    {
                        throw new CrossProfileOperationException();
                    }

                    if (scheduleEntry != null && scheduleEntry.CustomerGroup != null && scheduleEntry.CustomerGroup.Profile != dbProfile)
                    {
                        throw new CrossProfileOperationException("Group not belong to this user");
                    }
                    if (scheduleEntry != null && scheduleEntry.Activity.Profile != dbProfile)
                    {
                        throw new CrossProfileOperationException("Activity is not belong to this user");
                    }

                    if (itemsToSave.Where(x => x != entry && (
                                              x.StartTime <= entry.StartTime &&
                                              x.EndTime > entry.StartTime ||
                                              x.StartTime < entry.EndTime &&
                                              x.EndTime >= entry.EndTime))
                        .Count() > 0)
                    {
                        throw new AlreadyOccupiedException();
                    }

                    var dto = saveScheduleEntryRangeParam.Entries[newDb.IndexOf(entry)];
                    //if (dto.RemindBefore!=null)
                    //{
                    //    if(entry.Reminder==null)
                    //    {
                    //        entry.Reminder=new ReminderItem();
                    //    }
                    //    entry.Reminder.Profile = dbProfile;
                    //    entry.Reminder.DateTime = entry.StartTime;
                    //    entry.Reminder.RemindBefore = dto.RemindBefore==TimeSpan.Zero?(TimeSpan?) null:dto.RemindBefore.Value;
                    //    entry.Reminder.Name = string.Format("{0}: {1}", entry.Activity.Name,entry.StartTime);
                    //    entry.Reminder.Type = ReminderType.ScheduleEntry;
                    //}
                    if (dto.RemindBefore != null)
                    {
                        ReminderService.CreateReminder <ScheduleEntryDTO>(Session, entry, dto.RemindBefore, dbProfile,
                                                                          entry.StartTime, ReminderType.ScheduleEntry);
                    }
                    entry.Profile = dbProfile;
                    if (dto.MyPlaceId == null)
                    {
                        entry.MyPlace = Session.QueryOver <MyPlace>().Where(x => x.Profile == dbProfile && x.IsDefault).SingleOrDefault();
                    }
                    if (entry.MyPlace.Profile != dbProfile)
                    {
                        throw new CrossProfileOperationException("MyPlace not belong to this user");
                    }
                    if (!copy)
                    {
                        //save only when we are in saving mode. in copy mode this loop is only for checking and preparing
                        itemsToSave[index] = Session.Merge(entry);

                        if (dto.RemindBefore != null)
                        {
                            itemsToSave[index].Reminder.ConnectedObject = string.Format("ScheduleEntryDTO:{0}", itemsToSave[index].GlobalId);
                            Session.Update(itemsToSave[index].Reminder);
                        }
                        else if (dbOldEntry.Reminder != null)
                        {
                            Session.Delete(dbOldEntry.Reminder);
                            dbOldEntry.Reminder             = null;
                            dbProfile.DataInfo.ReminderHash = Guid.NewGuid();
                        }
                    }
                }
                if (copy)
                {
                    itemsToSave = copyScheduleEntries(startDate, endDate, saveScheduleEntryRangeParam.CopyStart.Value, saveScheduleEntryRangeParam.CopyEnd.Value, itemsToSave, saveScheduleEntryRangeParam.Mode);
                }
                dbProfile.DataInfo.ScheduleEntryHash = Guid.NewGuid();
                trans.Commit();
                return(itemsToSave.Map <IList <ScheduleEntryBaseDTO> >());
            }
        }
        public CustomerDTO SaveCustomer(CustomerDTO customerDto)
        {
            Log.WriteWarning("SaveCustomer:Username={0},GlobalId={1}", SecurityInfo.SessionData.Profile.UserName, customerDto.GlobalId);

            if (!customerDto.IsNew && !SecurityInfo.Licence.IsInstructor)
            {
                throw new LicenceException("This feature is allowed for Instructor account");
            }

            var db = customerDto.Map <Customer>();

            using (var trans = Session.BeginSaveTransaction())
            {
                Profile          dbProfile   = Session.Load <Profile>(SecurityInfo.SessionData.Profile.GlobalId);
                Picture          oldPicture  = null;
                Wymiary          oldWymiary  = null;
                Customer         oldCustomer = null;
                Address          oldAddress  = null;
                CustomerSettings oldSettings = null;

                bool oldIsVirtual;
                //if (!customerDto.IsNew)
                //{
                //    db = Session.Get<Customer>(customerDto.GlobalId);
                //    oldPicture = db.Picture;
                //    oldWymiary = db.Wymiary;
                //    oldSettings = db.Settings;
                //    oldIsVirtual = db.IsVirtual;
                //    Mapper.Map(customerDto, db);

                //    if(oldIsVirtual!=db.IsVirtual)
                //    {
                //        throw new InvalidOperationException("Cannot change IsVirtual for existing customer");
                //    }
                //}
                //else
                //{
                //    db = customerDto.Map<Customer>();
                //    db.CreationDate = Configuration.TimerService.UtcNow;
                //    db.Settings = new CustomerSettings();
                //    db.Profile = dbProfile;
                //}

                if (db.IsNew)
                {
                    db.CreationDate = Configuration.TimerService.UtcNow;
                    db.Settings     = new CustomerSettings();
                }
                else
                {
                    oldCustomer = Session.QueryOver <Customer>().Where(x => x.GlobalId == db.GlobalId)
                                  .Fetch(x => x.Address).Eager
                                  .Fetch(x => x.Wymiary).Eager
                                  .Fetch(x => x.Settings).Eager
                                  .Fetch(x => x.Picture).Eager
                                  .SingleOrDefault();
                    if (oldCustomer != null)
                    {
                        if (dbProfile != oldCustomer.Profile)
                        {
                            throw new CrossProfileOperationException("Cannot modify Customer for another user");
                        }

                        oldPicture   = oldCustomer.Picture;
                        oldWymiary   = oldCustomer.Wymiary;
                        oldAddress   = oldCustomer.Address;
                        oldSettings  = oldCustomer.Settings;
                        oldIsVirtual = oldCustomer.IsVirtual;
                        if (oldIsVirtual != db.IsVirtual)
                        {
                            throw new InvalidOperationException("Cannot change IsVirtual for existing customer");
                        }
                    }
                }


                db.Profile = dbProfile;

                if (customerDto.ConnectedAccount != null)
                {
                    Guid connectedAccountId     = customerDto.ConnectedAccount.GlobalId;
                    var  connectedAccountExists =
                        Session.QueryOver <Customer>().Where(x => x.Profile == dbProfile && x.GlobalId != db.GlobalId &&
                                                             x.ConnectedAccount.GlobalId == connectedAccountId
                                                             ).RowCount();
                    if (connectedAccountExists > 0)
                    {
                        throw new AlreadyOccupiedException("Specified ConnectedAccount is already used");
                    }
                    db.ConnectedAccount = Session.Get <Profile>(connectedAccountId);
                }
                else
                {
                    db.ConnectedAccount = null;
                }

                if (db.Wymiary != null && db.Wymiary.IsEmpty)
                {
                    Log.WriteVerbose("Wymiary is empty.");
                    if (!db.Wymiary.IsNew && (oldWymiary == null || db.Wymiary.GlobalId != oldWymiary.GlobalId))
                    {
                        Log.WriteInfo("Delete wymiary from db");
                        Session.Delete(db.Wymiary);
                    }
                    db.Wymiary = null;
                }

                if (oldWymiary != null && (db.Wymiary == null || oldWymiary.GlobalId != db.Wymiary.GlobalId))
                {
                    Session.Delete(oldWymiary);
                }

                if (db.Settings == null)
                {
                    throw new ArgumentNullException("Settings cannot be null");
                }


                if (db.Address != null && db.Address.IsEmpty)
                {
                    Log.WriteVerbose("Address is empty.");
                    if (!db.Address.IsNew && (oldAddress == null || db.Address.GlobalId != oldAddress.GlobalId))
                    {
                        Log.WriteInfo("Delete Address from db");
                        Session.Delete(db.Address);
                    }
                    db.Address = null;
                }

                if (oldAddress != null && (db.Address == null || oldAddress.GlobalId != db.Address.GlobalId))
                {
                    Session.Delete(oldAddress);
                }

                if (oldSettings != null && oldSettings.GlobalId != db.Settings.GlobalId)
                {
                    Session.Delete(oldSettings);
                }

                if (db.Birthday != null)
                {
                    var reminderService = new ReminderService(Session, SecurityInfo, Configuration);
                    reminderService.PrepareReminder(dbProfile, customerDto, db, oldCustomer, db.Birthday.Value.Date,
                                                    ReminderType.Birthday, ReminderRepetitions.EveryYear);
                }
                else if (oldCustomer != null && oldCustomer.Reminder != null)
                {
                    Session.Delete(oldCustomer.Reminder);
                    oldCustomer.Reminder            = null;
                    dbProfile.DataInfo.ReminderHash = Guid.NewGuid();
                }

                //remove old picture;
                PictureService pictureService = new PictureService(Session, SecurityInfo, Configuration);
                pictureService.DeletePictureLogic(oldPicture, customerDto.Picture);


                db = Session.Merge(db);
                dbProfile.DataInfo.CustomerHash = Guid.NewGuid();
                if (db.Reminder != null)
                {
                    db.Reminder.ConnectedObject = string.Format("CustomerDTO:{0}", db.GlobalId);
                    Session.Update(db.Reminder);
                    //TODO:Update datainfo for reminder
                }

                if (db.Settings.AutomaticUpdateMeasurements)
                {
                    MeasurementsAutomaticUpdater.Update(Session, dbProfile, db, Configuration.TimerService.UtcNow);
                }

                trans.Commit();
                return(db.Map <CustomerDTO>());
            }
        }