--- /dev/null
+Seat-Plans
+===========
+
+Server Side Minimum:
+---------------------
+
+<SeatPlan version="1">
+ <Group capacity="123" id="pr" name="Premium" numbered="no" price="1 3"/>
+ <Group capacity="234" id="ch" name="Cheapo" numbered="no" price="2 4"/>
+</SeatPlan>
+
+In this simplest form there are two kinds of seats: "Premium" and "Cheapo".
+In both cases seats are unnumbered (i.e. audience members can chose freely).
+
+<SeatPlan> defines the complete plan
+ version - version number of this spec, it is generally assumed that newer
+ versions are backwards compatible
+<Group> defines one group of seats
+ capacity - specifies how many seats there are in this group
+ id - automatically generated ID for groups, must only contain letters and
+ digits, max. 8 chars, no spaces
+ name - human readable name for the group
+ numbered - "yes": the seats have numbers, "no" audience members can freely chose
+ price - space separated list of pricecategory IDs for price levels that can be
+ sold in this group, if missing: all categories of the event
+
+
+To number seats by row add Row-elements to the Group tag:
+
+<SeatPlan version="1">
+ <Group capacity="123" id="pr" name="Premium" numbered="yes">
+ <Row id="2" capacity="23" first="2"/>
+ <Row id="3" capacity="25"/>
+ <Row id="4" capacity="25"/>
+ <Row id="5" capacity="25"/>
+ <Row id="6" capacity="25"/>
+ </Group>
+ <Group name="Expensive" id="ex" numbered="yes">
+ <Row id="" capacity="25"/>
+ <Row id="" capacity="25" first="26"/>
+ </Group>
+ <Group capacity="234" id="ch" name="Cheapo" numbered="no"/>
+</SeatPlan>
+
+In this case the Premium Group consists of rows 2..6, with row 2 numbered 2..24
+and rows 3..6 numbered 1..25 each. The capacity attribute of the Group tag must
+match the sum of row capacities.
+
+<Row> defines a single row of seats inside this group
+ id - a free form ID for the row, must only contain letters and digits,
+ may be empty, but no spaces
+ capacity - number of seats in this row
+ first - a number if counting does not start at 1
+
+If two rows have identical IDs then the seat numbers in those rows must be unique.
+E.g. above: in the Expensive group above both rows use the empty ID, one of them
+has seats 1..25, the other 26..50. If both had for example a seat 25, then only one
+of those two seats could be sold, the other would be inaccessible.
+
+Rows are ignored for unnumbered groups, they may exist to generate graphical
+seat plans (see below).
+
+Groups may exist several times with different rows/seats. If this happens the
+group id, name, and numbering attributes must be identical on all instances.
+Graphical information may differ. Seats inside those instances must be
+unique (different row id and/or seat number).
+
+Seat Numbering
+----------------
+
+Seat numbers are stored as strings (max. 32 chars). They are constructed from:
+ * the group ID
+ * the row ID, or an empty string if there are no rows defined
+ * the seat number within the row or group
+ * fields are separated by colons
+
+E.g.:
+ "pr:2:13" - group "pr" (Premium above), row "2", seat number 13
+ "ex::42" - group "ex", row with empty ID, seat number "42"
+ "ch::" - group "ch", no numbering
+
+
+Graphical Seat Plans
+---------------------
+
+This part is never evaluated by the server, only by displays:
+
+<SeatPlan version="1" size="100 200">
+ <Group capacity="123" id="pr" name="Premium" numbered="yes" geo="0 20 100 100" bgcolor="#fcc">
+ <Row id="2" capacity="23" first="2" geo="10 0 90 10/>
+ <Row id="3" capacity="25" geo="0 20 100 30"/>
+ <Row id="4" capacity="25" geo="0 40 100 50"/>
+ <Row id="5" capacity="25" geo="0 60 100 70"/>
+ <Row id="6" capacity="25" geo="0 80 100 90"/>
+ </Group>
+ <Group name="Expensive" id="ex" numbered="yes" geo="0 100 100 130" bgcolor="#cfc">
+ <Row id="" capacity="25" geo="0 0 100 10"/>
+ <Row id="" capacity="25" first="26" geo="0 20 100 30"/>
+ </Group>
+ <Group capacity="234" id="ch" name="Cheapo" numbered="no" geo="0 140 100 200" bgcolor="black" fgcolor="white"/>
+</SeatPlan>
+
+New Attributes:
+ SeatPlan/size - relative canvas size, the actual canvas will be scaled to fit the display
+ Group/geo - geometry relative to the canvas, coordinates are: x-left, y-top, x-right, y-bottom
+ Row/geo - geometry relative to the Group
+ bgcolor - (Group/Row) background color
+ fgcolor - (Group/Row) foreground color
+ Group/angle - rotate the group (value in degrees)
+ Row/curve - row curvature, see below
+
+Colors: all web colors can be used by name, numeric values can be specified in hex
+either as "#rgb" or "#rrggbb".
+
+Curvature of Rows: a series of points at which to align seats... ?
+
+TODO: define trapezes(?), curved rows, etc.
+
+Additional Graphics
+--------------------
+
+The background of the seat plan can be defined in an additional element:
+
+<SeatPlan version="1" size="100 200">
+ <Group capacity="123" id="pr" name="Premium" numbered="yes" geo="0 20 100 100" bgcolor="#fcc"/>
+
+ <!-- create a rectangle -->
+ <Background type="rect" geo="10 10 30 30" bgcolor="yellow"/>
+
+ <!-- create a simple text -->
+ <Background type="text" geo="10 10 30 30" fgcolor="darkblue" fontsize="15" content="hello"/>
+
+ <!-- create a circle or elipse -->
+ <Background type="circle" geo="40 40 50 60" bgcolor="lightred"/>
+</SeatPlan>
+
+Attributes:
+ bgcolor - background or fill color (not for Text)
+ fgcolor - foreground (Text) or outline color
+ geo - full size of the shape
+ angle - rotation in degree
+ Text/fontsize - font size in relative points of the seat plan, automatically scaled
+ Text/content - textual content
+
+Specifying Seats in Orders
+---------------------------
+
+No seat specified in cart order:
+1) The system tries to find a group that matches the price category,
+2) if the category does not have enough seats: continue search at 1
+3) if the category is unnumbered: use it, done
+4) if the category is numbered: try to find continuous seats in the same row
+5) not enough continuous seats: continue searching at 1
+6) if there are no more categories, repeat the search, but allow non-continuous seats
+
+Separately specified rows with the same ID are assumed to be continuous in the order
+of seat numbers. E.ฤก. if seats 1 and 2 of row "1" are specified in a different group than
+seats 3..23, then the algorithm still considers seats 2 and 3 to be side by side.
+
+Specified seats:
+The seat property contains a list of seat numbers (see above), separated by spaces, there must be
+exactly as many seats specified as there are tickets in this line item of the order.
+
+Wildcards:
+Seats can be specified with wildcards:
+ "ex" - chose any row and seat from group "ex"
+ "ex:2" - chose any seat from the row "2" in "ex"
+ "ex:2|3|4" - chose any seat from rows "2", "3" or "4" in "ex"
+ "ex|pr" - chose any seats from groups ex or pr
+ "ex|pr:2" - chose any seats on row "2" that are in group ex or pr
+ "ex|pr:2|3:4" - chose any seat with the number 4 if it is in ex or pr and on rows 2 or 3
+ "ex:2:4|6" - chose seat 4 or 6 from row 2 in group ex
+ "ex:2:4-16" - chose between seats 4 through 16 on row 2 in group ex
+ "*:*:4-16" - chose between seats 4 through 16 on any row in any group
+The algorithm used to select seats is the same as the one for specifying no seats at all,
+except that choices are limited to seats matching the pattern. In fact specifying no seats
+is equivalent to the most unspecific pattern: "" or "*:*:*".
+
+Pattern grouping: "group:row:seat" with "group:row" being equivalent to "group:row:*" and
+"group" equivalent to "group:*" or "group:*:*". The empty pattern "" is equivalent to "*:*:*".
+
+Pattern syntax:
+ "string" - match exactly string
+ "*" - match any value
+ "" - match the empty value only!
+ "s1|s2" - match s1 or s2
+ "1-3" - match any value between 1 and 3 (including), only allowed for seat numbers
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Seat Plan Definition MagicSmoke WOLF
+ - declares everything needed to define seat plans
+ -
+ - (c) Konrad Rosenbaum, 2013
+ - this file is protected under the GNU AGPLv3 or at your option any newer
+ - see COPYING.AGPL for details
+ -->
+<Wolf>
+ <Class name="SeatPlanRow">
+ <Doc>This is a helper for parsing seat plans: it defines a row of seats</Doc>
+ <Property name="id" type="astring">the ID of this group, if multiple row elements with the same ID exist, they refer to different sections of the same row</Property>
+ <Property name="capacity" type="int">amount of seats in this (part of the) row</Property>
+ <Property name="geo" type="astring">GUI: geometry information for the row</Property>
+ <Property name="bgcolor" type="astring">GUI: background color for seats</Property>
+ <Property name="fgcolor" type="astring">GUI: foreground color, the one the seat number is rendered in</Property>
+ <Property name="first" type="int">number of the first seat in this row</Property>
+ </Class>
+ <Class name="SeatPlanGroup">
+ <Doc>This is a helper for parsing seat plans: it defines a group of rows of seats.</Doc>
+ <Property name="id" type="astring">the ID of this group, if multiple group elements with the same ID exist, they refer to different sections of the same group</Property>
+ <Property name="capacity" type="int">amount of seats in this (part of the) group</Property>
+ <Property name="name" type="astring">human readable name of the group</Property>
+ <Property name="numbered" type="bool">defines whether the group contains numbered seats</Property>
+ <Property name="geo" type="astring">GUI: geometry information for the group</Property>
+ <Property name="bgcolor" type="astring">GUI: background color</Property>
+ <Property name="fgcolor" type="astring">GUI: foreground color, the one the group name is rendered in</Property>
+ <Property name="angle" type="int">GUI: rotation of the group rectangle</Property>
+ <Property name="Row" type="List:SeatPlanRow">definition of rows in this group</Property>
+ </Class>
+
+ <Class name="SeatPlanBackground">
+ <Property name="type" type="astring">Type of background element, e.g. "circle", "rect", ...</Property>
+ <Property name="geo" type="astring">GUI: geometry information for the group</Property>
+ <Property name="bgcolor" type="astring">GUI: background or fill color</Property>
+ <Property name="fgcolor" type="astring">GUI: foreground, outline or text color</Property>
+ <Property name="angle" type="int">GUI: rotation of the group rectangle</Property>
+ <Property name="fontsize" type="int">GUI: font size for text elements</Property>
+ <Property name="content" type="astring">GUI: textual content</Property>
+ </Class>
+
+ <Class name="SeatPlan">
+ <Doc>This class is used to parse seat plans on either side.</Doc>
+ <Property name="Group" type="List:SeatPlanGroup"/>
+ <Property name="Background" type="List:SeatPlanBackground"/>
+ </Class>
+</Wolf>