module DredgePos.Floorplan.Model open DredgePos.Types open System open System.IO open System.Xml.Linq open DredgeFramework open Dapper.FSharp open Thoth.Json.Net let activeTablePath = "tables/active/" let getTableFile (tableNumber: int) = let tableNumberString = tableNumber |> string activeTablePath + "table" + tableNumberString + ".table" let tableNumberIsOpen (tableNumber: int) = let tableFile = getTableFile tableNumber File.Exists tableFile let tableIsOpen (table: floorplan_table) = tableNumberIsOpen table.table_number let fileNameToTableNumber (fileName: string) = //Takes a file name for a floorplan table and returns the table number if fileName.Contains ".table" then let fileName = (fileName.Split ".")[0] (fileName.Split "/table")[1] |> int else 0 let openTables () = //Get a list of all open tables. let tableList = Directory.GetFiles(activeTablePath) tableList |> Array.map fileNameToTableNumber |> Array.filter(fun tableNumber -> tableNumber > 0) let getTableNumber table = table.table_number let tablesInRoom (roomId: int) = //Get a list of all tables in a particular room. select { table "floorplan_tables" where (eq "room_id" roomId) } |> Database.Select let getActiveTables (venueId: int) = select{ table "floorplan_tables" where (eq "venue_id" venueId) } |> Database.Select |> Array.filter tableIsOpen |> Array.map (fun table -> table.table_number) let openNewTable tableNumber = //Create a new table file pre-populated with skeleton data let tableFile = getTableFile tableNumber if not <| File.Exists tableFile then let newTableTemplate = $"""
""" File.Create tableFile |> ignore File.WriteAllText (tableFile, newTableTemplate) let transferTable origin destination = //Transfers a table from one to another let originFile = getTableFile origin let destinationFile = getTableFile destination if tableNumberIsOpen origin then (* If the destination is not an already open table, then we simply have to rename the origin to destination *) if not <| tableNumberIsOpen destination then let content = File.ReadAllText originFile let newContent = content.Replace($"number=\"{origin|>string}\">", $"number=\"{destination|>string}\">") File.WriteAllText(originFile, newContent) File.Move(originFile, destinationFile) else let originXML = XDocument.Load originFile let destinationXML = XDocument.Load destinationFile destinationXML.Root.Add(originXML.Root.Elements()) destinationXML.Save destinationFile File.Delete originFile let saveOrderToTable orderXML tableNumber = let tableFile = getTableFile tableNumber let tableXML = tableFile |> File.ReadAllText |> StringReplace "" (orderXML + "") File.WriteAllText(tableFile, tableXML) let getTableSafely (tableNumber: int) = let query = select { table "floorplan_tables" where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue())) } query |> Database.Select |> Array.tryItem 0 let getTable (tableNumber : int) = match getTableSafely tableNumber with | None -> failwith $"Table {tableNumber} not found in current venue" | Some table -> table let getTableById (id : int) = select { table "floorplan_tables" where (eq "id" id) } |> Database.Select |> first let getRoom (roomId: int) = select { table "rooms" where (eq "id" roomId) } |> Database.Select |> first let updateTablePosition (floorplanTable: floorplan_table) = Entity.Update floorplanTable let createEmptyReservation (reservation: reservation) = update { table "floorplan_tables" set {| status = 2 |} where(eq "id" reservation.floorplan_table_id) } |> Database.Update |> ignore Entity.Create reservation let getChildTables tableNumber = let table = getTable tableNumber let json = table.merged_children let result = json |> Decode.Auto.fromString match result with | Ok tables -> tables | Error _ -> [||] let matchTable (tableNumberToMatch: int) (floorplanTableToCheck: floorplan_table) = tableNumberToMatch = floorplanTableToCheck.table_number let findChildTable (childTable: int) (parentTable: floorplan_table) = let json = parentTable.merged_children let childTables = json |> Decode.Auto.fromString let matchedTables = match childTables with | Ok table -> table |> Array.map(matchTable childTable) | Error _ -> [|false|] |> removeFalseValues |> length match matchedTables with | 0 -> 0 | _ -> parentTable.table_number let tableExists (tableNumber: int) = let numberOfResults = select{ table "floorplan_tables" where (eq "table_number" tableNumber + eq "venue_id" (getCurrentVenue())) } |> Database.Select |> length match numberOfResults with | 0 -> let allTables = Entity.GetAllInVenue |> Array.map(findChildTable tableNumber) |> Array.filter(fun tableNumber -> tableNumber <> 0) match allTables.Length with | 0 -> false |> string //Table does not exist | _ -> let parentTableData = getTable allTables[0] let parentRoom = getRoom parentTableData.room_id let parentRoomName = parentRoom.name language.getAndReplace "error_table_exists_merged" [parentRoomName; parentTableData.table_number.ToString()] | _ -> let tableData = getTable tableNumber let room = getRoom tableData.room_id language.getAndReplace "error_table_exists" [room.name] let addNewTableWithoutOutput (newTable: floorplan_table) = insert{ table "floorplan_tables" value newTable } |> Database.Insert let addNewTable (newTable: floorplan_table) = Entity.Create newTable let mergeTables parent child = //Merge two tables together if parent = child then false else let parentTable = getTable parent let childTable = getTable child let xDiff = (parentTable.pos_x - childTable.pos_x) |> Math.Abs let yDiff = (parentTable.pos_y - childTable.pos_y) |> Math.Abs let newHeight = if xDiff < yDiff then parentTable.height + childTable.height else parentTable.height let newWidth = if xDiff >= yDiff then parentTable.width + childTable.width else parentTable.width let newPosX = if parentTable.pos_x <= childTable.pos_x then parentTable.pos_x + xDiff/2 else parentTable.pos_x - xDiff/2 let newPosY = if parentTable.pos_y <= childTable.pos_y then parentTable.pos_y + yDiff/2 else parentTable.pos_y - yDiff/2 let newChildTable = childTable let existingChildrenJson = parentTable.merged_children |> StringTrim let existingChildren = existingChildrenJson |> Decode.Auto.fromString let tableList = match existingChildren with | Error _ -> [|newChildTable|] | Ok tables -> [tables ; [|newChildTable|]] |> Array.concat let newChildrenJson = tableList |> jsonEncode let parentPreviousState = parentTable |> jsonEncode update { table "floorplan_tables" set {| merged_children = newChildrenJson previous_state = parentPreviousState height = newHeight width = newWidth pos_x = newPosX pos_y = newPosY default_covers = parentTable.default_covers + childTable.default_covers |} where (eq "table_number" parent + eq "venue_id" (getCurrentVenue())) } |> Database.Update |> ignore Entity.DeleteById newChildTable.id |> ignore true let updateUnmergedTables parentTable childTable = update { table "floorplan_tables" set parentTable where(eq "table_number" parentTable.table_number + eq "venue_id" (getCurrentVenue())) } |> Database.Update |> ignore addNewTableWithoutOutput childTable |> ignore true let processUnmerge originalTable unmergedChild = let previousState = originalTable.previous_state |> Decode.Auto.fromString match previousState with | Ok table -> updateUnmergedTables table unmergedChild | Error _ -> false let unmergeTable tableNumber = //Separates a merged table into itself and the last table merged into it. let currentTable = getTable tableNumber let mergedChildren = currentTable.merged_children |> Decode.Auto.fromString match mergedChildren with | Ok listOfChildTables -> let unmergedChild = listOfChildTables |> last processUnmerge currentTable unmergedChild |> ignore Some (getTable currentTable.table_number, unmergedChild) | Error _ -> None let getReservationList (tableList: floorplan_table[]) = tableList |> Array.collect Entity.GetAllRelated let newReservation name time covers = let reservation = { id = 0 name = name time = time covers = covers floorplan_table_id = 0 created_at = CurrentTime() } Entity.Create reservation let tableList () = Entity.GetAllInVenue