/// <summary>
        /// Updates a dangerous zone
        /// </summary>
        /// <param name="m"></param>
        public static void UpdateZone(ZoneModel m)
        {
            var db = new BicikliDataClassesDataContext();
            var zoneToUpdate = db.DangerousZones.Single(z => z.id == m.id);

            if (zoneToUpdate.description != m.description)
            {
                zoneToUpdate.description = m.description;
            }
            if (zoneToUpdate.latitude != m.latitude)
            {
                zoneToUpdate.latitude = m.latitude;
            }
            if (zoneToUpdate.longitude != m.longitude)
            {
                zoneToUpdate.longitude = m.longitude;
            }
            if (zoneToUpdate.name != m.name)
            {
                zoneToUpdate.name = m.name;
            }
            if (zoneToUpdate.radius != m.radius)
            {
                zoneToUpdate.radius = m.radius;
            }

            db.SubmitChanges();
        }
 /// <summary>
 /// Updates a bike in the database
 /// </summary>
 /// <param name="m"></param>
 public static void UpdateBike(BikeModel m)
 {
     var db = new BicikliDataClassesDataContext();
     var bikeToUpdate = db.Bikes.Single(b => b.id == m.id);
     if (bikeToUpdate.name != m.name)
     {
         bikeToUpdate.name = m.name;
     }
     if (bikeToUpdate.description != m.description)
     {
         bikeToUpdate.description = m.description;
     }
     if (bikeToUpdate.is_active != m.isActive)
     {
         bikeToUpdate.is_active = m.isActive;
     }
     if (bikeToUpdate.current_lender_id != m.currentLenderId)
     {
         bikeToUpdate.current_lender_id = m.currentLenderId;
     }
     if (bikeToUpdate.image_url != m.imageUrl)
     {
         bikeToUpdate.image_url = m.imageUrl;
     }
     db.SubmitChanges();
 }
 /// <summary>
 /// Deletes a dangerous zone
 /// </summary>
 /// <param name="id"></param>
 public static void DeleteZone(int id)
 {
     var db = new BicikliDataClassesDataContext();
     var zoneToRemove = db.DangerousZones.Single(z => z.id == id);
     if (zoneToRemove.Sessions.Count() > 0)
     {
         foreach (Session s in zoneToRemove.Sessions)
         {
             s.dz_id = null;
         }
     }
     db.DangerousZones.DeleteOnSubmit(zoneToRemove);
     db.SubmitChanges();
 }
        /// <summary>
        /// Inserts a new Zone into the database
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public static int InsertZone(ZoneModel m)
        {
            var db = new BicikliDataClassesDataContext();
            var zoneToInsert = new DangerousZone()
            {
                description = m.description,
                latitude = m.latitude,
                longitude = m.longitude,
                name = m.name,
                radius = m.radius
            };
            db.DangerousZones.InsertOnSubmit(zoneToInsert);
            db.SubmitChanges();

            return zoneToInsert.id;
        }
        /// <summary>
        /// Updates Lender-User assignments
        /// </summary>
        /// <param name="lender_id">Lender ID</param>
        /// <param name="users">username list</param>
        public static void UpdateAssignments(int lender_id, string[] users)
        {
            var db = new BicikliDataClassesDataContext();

            #region Step 1: Extract selected user guids

            var guidsToInsert = new HashSet<Guid>();
            if (users != null)
            {
                foreach (string username in users)
                {
                    var msUser = Membership.GetUser(username);
                    if (msUser != null)
                    {
                        Guid msUserGuid = (Guid)msUser.ProviderUserKey;
                        if (!guidsToInsert.Contains(msUserGuid))
                        {
                            guidsToInsert.Add(msUserGuid);
                        }
                    }
                }
            }

            #endregion

            #region Step 2: Apply changes to assignments

            #region Insert new assignments

            var lenderGuidAssignments = DataRepository.GetLenderAssignedGuids(lender_id);
            foreach (Guid guid in guidsToInsert)
            {
                if (!lenderGuidAssignments.Contains(guid))
                {
                    var luToInsert = new LenderUser();
                    luToInsert.user_id = guid;
                    luToInsert.lender_id = lender_id;
                    db.LenderUsers.InsertOnSubmit(luToInsert);
                }
            }

            #endregion

            #region Delete removed assignments

            lenderGuidAssignments = DataRepository.GetLenderAssignedGuids(lender_id);
            foreach (Guid guid in lenderGuidAssignments)
            {
                if (!guidsToInsert.Contains(guid))
                {
                    var luToDelete = db.LenderUsers.Where(lu => (lu.lender_id == lender_id) && (lu.user_id == guid)).First();
                    db.LenderUsers.DeleteOnSubmit(luToDelete);
                }
            }

            #endregion
            
            db.SubmitChanges();

            #endregion
        }
 /// <summary>
 /// Removes a printer from a lender
 /// </summary>
 /// <param name="lender_id"></param>
 public static void RemovePrinter(int lender_id)
 {
     var db = new BicikliDataClassesDataContext();
     var lenderWithPrinter = db.Lenders.Single(l => l.id == lender_id);
     lenderWithPrinter.printer_ip = null;
     db.SubmitChanges();
 }
        /// <summary>
        /// Inserts a Lender, then returns the generated primary key
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static int InsertLender(LenderModel model)
        {
            var db = new BicikliDataClassesDataContext();
            var lenderToInsert = new Lender();
            lenderToInsert.name = model.name;
            lenderToInsert.address = model.address;
            lenderToInsert.description = model.description;
            lenderToInsert.printer_ip = model.printer_ip;
            lenderToInsert.latitude = model.latitude;
            lenderToInsert.longitude = model.longitude;

            if ((model.printer_password != null) && (model.printer_password != ""))
            {
                lenderToInsert.printer_password = model.printer_password;
            }
            else
            {
                lenderToInsert.printer_password = ((int)(new Random().NextDouble() * 899999) + 100000).ToString();
            }

            db.Lenders.InsertOnSubmit(lenderToInsert);
            db.SubmitChanges();

            return lenderToInsert.id;
        }
        /// <summary>
        /// Updates a Session in the database
        /// </summary>
        /// <param name="m"></param>
        public static void UpdateSession(SessionModel m)
        {
            var db = new BicikliDataClassesDataContext();
            var invoiceToUpdate = db.Sessions.Single(s => s.id == m.id);

            if (invoiceToUpdate.name != m.name)
            {
                invoiceToUpdate.address = m.name;
            }
            if (invoiceToUpdate.address != m.address)
            {
                invoiceToUpdate.address = m.address;
            }
            if (invoiceToUpdate.end_time != m.endTime)
            {
                invoiceToUpdate.end_time = m.endTime;
            }
            if (invoiceToUpdate.paid != m.paid)
            {
                invoiceToUpdate.paid = m.paid;
            }
            db.SubmitChanges();
        }
        /// <summary>
        /// Updates user assignments
        /// </summary>
        /// <param name="guid"></param>
        /// <param name="lenders"></param>
        public static void UpdateUserAssignments(string username, int[] lenders)
        {
            Guid guid = (Guid)Membership.GetUser(username).ProviderUserKey;

            if (lenders != null)
            {
                var lendersToInsert = new List<int>();
                foreach (int l in lenders)
                {
                    if (!lendersToInsert.Contains(l))
                    {
                        lendersToInsert.Add(l);
                    }
                }
                var assignedLenders = DataRepository.GetLendersOfUser(guid);
                var lendersToRemove = new List<int>();
                foreach (LenderModel lm in assignedLenders)
                {
                    if (lendersToInsert.Contains((int)lm.id))
                    {
                        lendersToInsert.Remove((int)lm.id);
                    }
                    else
                    {
                        lendersToRemove.Add((int)lm.id);
                    }
                }

                var db = new BicikliDataClassesDataContext();
                foreach (int l in lendersToRemove)
                {
                    db.LenderUsers.DeleteOnSubmit(db.LenderUsers.First(s => ((s.lender_id == l) && (s.user_id == guid))));
                }
                foreach (int l in lendersToInsert)
                {
                    db.LenderUsers.InsertOnSubmit(new LenderUser() { lender_id = l, user_id = guid });
                }
                db.SubmitChanges();
            }
            else
            {
                var db = new BicikliDataClassesDataContext();
                db.LenderUsers.DeleteAllOnSubmit(db.LenderUsers.Where(s => (s.user_id == guid)));
                db.SubmitChanges();
            }
        }
        /// <summary>
        /// Deletes a lender
        /// </summary>
        /// <param name="lender_id"></param>
        public static void DeleteLender(int lender_id)
        {
            var dc = new BicikliDataClassesDataContext();
            var lenderToRemove = dc.Lenders.Where(l => l.id == lender_id).Single();
            foreach (Bike bike in lenderToRemove.Bikes)
            {
                bike.current_lender_id = null;
            }
            dc.SubmitChanges();

            dc.LenderUsers.DeleteAllOnSubmit(lenderToRemove.LenderUsers);
            dc.SubmitChanges();

            dc.Lenders.DeleteOnSubmit(lenderToRemove);
            dc.SubmitChanges();
        }
 /// <summary>
 /// Updates the Invoice configuration
 /// </summary>
 /// <param name="normal_price"></param>
 /// <param name="danger_price"></param>
 /// <param name="normal_vat"></param>
 /// <param name="danger_vat"></param>
 public static void UpdateInvoiceConfig(int normal_price, int danger_price, float normal_vat, float danger_vat)
 {
     var db = new BicikliDataClassesDataContext();
     db.Configurations.Single(c => c.key == "normal_price").value = normal_price.ToString();
     db.Configurations.Single(c => c.key == "danger_price").value = danger_price.ToString();
     db.Configurations.Single(c => c.key == "normal_vat").value = normal_vat.ToString();
     db.Configurations.Single(c => c.key == "danger_vat").value = danger_vat.ToString();
     db.SubmitChanges();
 }
        /// <summary>
        /// Creates a new session
        /// </summary>
        /// <param name="m"></param>
        public static int CreateSession(SessionModel m)
        {
            var db = new BicikliDataClassesDataContext();
            var invoiceToInsert = new Session()
            {
                bike_id = m.bike_id,
                name = m.name,              // user data (name)
                address = m.address,        // user data (address)
                dz_id = null,
                dz_time = 0,
                end_time = null,
                last_report = null,
                latitude = null,
                longitude = null,
                normal_time = 0,
                paid = false,
                start_time = DateTime.Now,
                normal_price = DataRepository.GetNormalUnitPrice(),
                normal_vat = DataRepository.GetNormalVAT(),
                danger_price = DataRepository.GetDangerousUnitPrice(),
                danger_vat = DataRepository.GetDangerousVAT()
            };
            db.Sessions.InsertOnSubmit(invoiceToInsert);
            db.Bikes.Single(b => b.is_active && (b.id == m.bike_id)).current_lender_id = null;
            db.SubmitChanges();

            return invoiceToInsert.id;
        }
        /// <summary>
        /// Reports a session
        /// </summary>
        /// <param name="m"></param>
        public static void ReportSession(SessionModel m)
        {
            var db = new BicikliDataClassesDataContext();
            var report = db.Sessions.Single(s => s.id == m.id);

            report.dz_id = m.dangerousZoneId;
            report.dz_time = m.dangerousZoneTime;
            report.normal_time = m.normalTime;
            report.last_report = m.lastReport;
            report.latitude = m.latitude;
            report.longitude = m.longitude;

            if (report.end_time != m.endTime)
            {
                report.end_time = m.endTime;
            }

            db.SubmitChanges();
        }
        /// <summary>
        /// Inserts a bike into the database
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        public static int InsertBike(BikeModel m)
        {
            var db = new BicikliDataClassesDataContext();
            var bike = new Bike()
                {
                    description = m.description,
                    is_active = m.isActive,
                    name = m.name,
                    current_lender_id = m.currentLenderId
                };
            db.Bikes.InsertOnSubmit(bike);
            db.SubmitChanges();

            return bike.id;
        }
        /// <summary>
        /// Updates a Lender
        /// </summary>
        /// <param name="model"></param>
        public static void UpdateLender(LenderModel model)
        {
            var db = new BicikliDataClassesDataContext();
            var lenderToUpdate = db.Lenders.First(l => l.id == model.id);

            lenderToUpdate.address = model.address;
            lenderToUpdate.description = model.description;
            lenderToUpdate.latitude = model.latitude;
            lenderToUpdate.longitude = model.longitude;
            lenderToUpdate.name = model.name;
            lenderToUpdate.printer_ip = model.printer_ip;

            if ((model.printer_password != null) && (model.printer_password != ""))
            {
                lenderToUpdate.printer_password = model.printer_password;
            }
            else
            {
                lenderToUpdate.printer_password = ((int)(new Random().NextDouble() * 899999) + 100000).ToString();
            }

            db.SubmitChanges();
        }
 /// <summary>
 /// Deletes a bike
 /// </summary>
 /// <param name="id"></param>
 public static void DeleteBike(int id)
 {
     var db = new BicikliDataClassesDataContext();
     db.Bikes.DeleteOnSubmit(db.Bikes.Single(b => b.id == id));
     db.SubmitChanges();
 }
        /// <summary>
        /// Sends an Invoice to a remote printer.
        /// </summary>
        /// <param name="session"></param>
        /// <param name="lender"></param>
        /// <returns></returns>
        public static bool sendInvoice(Models.SessionModel session, Models.LenderModel lender)
        {
            if ((session.endTime == null) && (lender.printer_ip != null))
            {
                return false;
            }

            var invoice = new InvoiceModel()
            {
                address = (session.address ?? "-"),
                name = (session.name ?? "-"),
                lender_name = (lender.name ?? "-"),
                lender_address = (lender.address ?? "-"),
                total_balance = (int)(session.totalBalance),
                bike_name = (session.bikeModel.name ?? "-"),
                items = new List<InvoiceItemModel>()
            };

            invoice.items.Add(new InvoiceItemModel()
            {
                title = "Normál zónában töltött idő",
                vat = (float)session.normal_vat,
                base_unit_price = session.normal_price,
                amount = (int) Math.Round((double)(session.normalTimeMinutes ?? 0))
            });

            invoice.items.Add(new InvoiceItemModel()
            {
                title = "Veszélyes zónában töltött idő",
                vat = (float)session.danger_vat,
                base_unit_price = session.danger_price,
                amount = (int)Math.Round((double)(session.dangerousZoneTimeMinutes ?? 0))
            });

            try
            {
                IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(lender.printer_ip), 6060);
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                try
                {
                    socket.Connect(remoteEP);
                    var stream = new StreamWriter(new NetworkStream(socket));
                    var serializer = new DataContractJsonSerializer(typeof(InvoiceModel));
                    using (MemoryStream memory = new MemoryStream())
                    {
                        serializer.WriteObject(memory, invoice);
                        stream.Write(Encoding.UTF8.GetString(memory.ToArray()));
                    }
                    stream.Flush();
                }
                catch
                {
                    try
                    {
                        var db = new BicikliDataClassesDataContext();
                        db.Lenders.Single(l => l.id == lender.id).printer_ip = null;
                        db.SubmitChanges();
                    }
                    catch { }

                    return false;
                }

                try
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                }
                catch { }
            }
            catch
            {
                return false;
            }

            return true;
        }