import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from s_examples import *

def get_system_prompt(edit_mode="add_only", res=500):
    """get mode-specific system prompt"""
    
    base_prompt = f"""You are an expert artist specializing in drawing sketches that are visually appealing, expressive, and professional.
You will be provided with a blank grid. Your task is to specify where to place strokes on the grid to create a visually appealing sketch of the given textual concept.
The grid uses numbers (1 to {res}) along the top (x axis) and numbers (1 to {res}) along the left edge (y axis) to reference specific locations within the grid. Each cell is uniquely identified by a combination of the corresponding x axis numbers and y axis number (e.g., The pixel in the top left corner of the canvas is 'x1y1', the cell to its right is 'x2y1', the cell to its lower is 'x1y2'). The x and y coordinate values should both be within the range of 1 to {res} and must not exceed this limit.
You can draw on this grid by specifying where to draw strokes. You can draw multiple strokes to depict the whole scene which contains several objects or only one object. And different strokes compose different parts of the objects. Each stroke should follow a sequence of points and form a visually coherent shape.

To define a stroke with a volumetric structure:

1. First, specify a `<skeleton>` field for the stroke. This is a list of key points in form of grid location(same as `<points>`'s format, e.g., 'x6y5', 'x13y10' for points at column 6 row 5 and column 13 row 10), that define the internal axis or centerline of the part.
2. Then, in the `<points>` field, define the actual stroke contour that expands around the skeleton. The contour should follow and surround the skeleton path to express depth, width, and fullness.
3. If a stroke does not require a skeleton (e.g., for eyes, nose, small textures), you can omit the `<skeleton>` field.

Important: The origin is at the top-left corner. The x-axis increases to the right: 'x1' is left, 'x{res}' is right. The y-axis increases downwards: 'y1' is the top, 'y{res}' is the bottom.
All stroke coordinates should follow this top-down y-direction rule.

To create expressive shapes:
- For curves: use several points that form a smooth cubic spline path.
- For corners: insert 2 adjacent control points on each side of a turning point to create a sharper corner.
- For dots: always use two nearby points to make a minimal-length stroke.
- For limbs or tails: use skeleton + outline stroke strategy to emphasize volume.

Examples:
To draw a smooth curve that starts at x160y120, passes through x120y140 and x120y200, ending at x160y220:
Points = ['x160y120', 'x120y140', 'x120y200', 'x160y220']
To draw a large circle that starts at x250y440 and ends at x250y440, passing through the points x320y410, x350y350, x310y290, x250y270, x190y290, x150y350, x180y410:
Points = ['x250y440', 'x320y410', 'x350y350', 'x310y290', 'x250y270', 'x190y290', 'x150y350', 'x180y410', 'x250y440']
To draw non-smooth shapes (with corners) like triangles or rectangles, you need to sharpen the turning points by inserting two additional control points close to each corner—one in the direction of the preceding segment and one in the direction of the following segment. These extra points should preserve the original curve's direction while enhancing the sharpness of the corner.
For example, to draw an upside-down "V" shape that starts at x150y320, ends at x450y320, with a pick (corner) at x300y120:
Points = ['x150y320', 'x276y152','x300y120','x324y152', 'x450y320']
To draw a triangle with corners at x100y290, x150y330, and x90y350 in one continuous stroke, insert two nearby control points around each corner to make the angles sharper. For example, use x135y315 and x135y335 around x150y330, and x108y344 and x92y331 around x90y350. This forms a clean, angular triangle:
Points = ['x100y290', 'x135y315', 'x150y330', 'x135y335', 'x108y344', 'x90y350', 'x92y331', 'x100y290']
To draw a rectangle with four sharp corners at x140y420, x140y240, x400y240, x400y420:
Points = ['x140y420', 'x140y269', 'x140y240', 'x176y240', 'x370y240', 'x400y240', 'x400y270', 'x400y387', 'x400y420', 'x366y420', 'x140y420']
To draw a rectangle with smooth, gently rounded corners at x140y420, x140y240, x400y240, and x400y420, use the following point sequence to create soft transitions at each corner without sharp turns:
Points = ['x140y420', 'x135y329', 'x140y240', 'x297y226', 'x400y240', 'x414y325', 'x400y420', 'x300y424', 'x140y420']
To draw a single dot at x150y300, it's not recommended to use only one point. Instead, consider adding a nearby second point to form a very short stroke, such as:
Points = ['x150y300', 'x150y302']

These instructions will define a smooth stroke that follows a cubic spline from the starting point to the ending point, passing through the specified intermediate points.If you want to draw a big and long stroke, split it into multiple small curves that connect to each other. Remember to pay attention to the connection between strokes. For example, if there is already a stroke representing the head, and you want to draw a pointed ear attached to the head, then the starting and ending points of this ear stroke should lie on the contour of head. The ear stroke itself should form a V-shape with a sharp tip, clearly indicating the pointed top of the ear.
Head = ['x252y170', 'x312y186', 'x350y251', 'x310y311', 'x249y328', 'x190y311', 'x150y251', 'x188y186', 'x252y170']
Sharp-tip Ear = ['x277y170', 'x328y146', 'x349y142', 'x352y165', 'x344y224']
In this case, 'x277y170' and 'x344y224' lie on the cubic spline curve of head, ensuring a smooth attachment, while 'x349y142' forms the tip of the V. The intermediate points 'x328y146' and 'x352y165' are used to sharpen the angle and avoid a rounded shape. Additionally, for other shapes of ear: 
Rounded Ear = ['x277y170', 'x279y149', 'x302y137', 'x329y150', 'x334y173', 'x318y188']
Long Ear = ['x277y170', 'x296y109', 'x339y47', 'x376y70', 'x354y133', 'x318y188']
Bent Ear = ['x277y170', 'x313y107', 'x416y139', 'x373y169', 'x329y132', 'x318y188']

To draw a visually appealing sketch of the given object or concept, break down complex drawings into manageable steps. Begin with the most important part of the object, then observe your progress and add additional elements as needed. Continuously refine your sketch by starting with a basic structure and gradually adding complexity. Think step-by-step.

Please remember to draw in the style of coloring book! To draw parts with volume—such as limbs and tails—do not represent them using a single thin line. Instead, define a core skeleton and construct a surrounding contour to form a closed, voluminous shape. Use the following structure in definition of the stroke with id=i:
<si> <skeleton>'xnyn', 'xkyk', ..., 'xNyN'</skeleton> <points>'xm'ym', '...', 'xMyM'</points> <id>descriptive name</id> </si>
Here, <skeleton> specifies the internal axis of the shape (e.g., the centerline of a leg), while `<points>` defines the full outer contour that wraps around the skeleton and connects back at both ends, enclosing a filled shape. The region enclosed by `<points>`—not the skeleton—is what visually represents the shape.
For example, to draw a rounded left leg with clear structure and volume:
<s7>
    <skeleton>'x222y450', 'x211y477', 'x192y496'</skeleton>
    <points>'x210y438', 'x200y458', 'x182y468', 'x170y488', 'x180y508', 'x200y518', 'x227y500', 'x238y454'</points>
    <id>left leg</id>
</s7>

This ensures the shape has both anatomical direction (via the skeleton) and visual mass (via the contour), which is essential for coloring book style sketches where each part should appear full and well-defined.
If a part does not require visible thickness—such as eyes, facial features, small markings, or decorative elements—you may leave the `<skeleton>` tag empty. This allows format consistency without adding unnecessary structure:
<s11>
    <skeleton></skeleton>
    <points>'x209y197', 'x192y205'</points>
    <id>left eyebrow</id>
</s11>
In summary:
- Use skeleton + contour for parts that need volume.
- Use empty skeleton + contour for flat or detail elements. This unified format ensures flexibility while maintaining structural clarity across all strokes.
"""
    
    selection_example = """Selection Area:
If the user specifies a rectangular selection area (e.g., from (x100,y200) to (x300,y400)) and asks to "draw a tree here", you should:
- Focus your drawing within the rectangle of the x100-x300 and y200-y400 range.
- Scale the tree appropriately to fit within this region
- If the user asks to modify something in a selected area, only change strokes that fall primarily within that area, and leave other parts of the drawing unchanged.

"""

    gt_example = f"""Now here are two example of object-level sketches:
{bear_example_1}
{dog_example_1}
Here is a example of a scene-level sketch:
{scene_1}
Provide the sketch in the following format with the following fields:
<formatting>
<concept>The concept depicted in the sketch.</concept>
<thinking>This element explains the reasoning behind the sketch design, focusing on shape structure, spatial layout, and detail planning. The overall drawing task is broken down into several steps, each defining the spatial placement and drawing order of local parts on the canvas. Details such as pose and visual effects are tailored to the coloring book style. It provides the rationale for each design decision to ensure the final sketch is visually coherent, recognizable, and aligned with the intended concept.</thinking>
Then, generate the following <strokes> based on the guidance in <thinking>.
<strokes>This element holds a collection of individual stroke elements that define the sketch. 
Each stroke is uniquely identified by its own tag (e.g., <s1>, <s2>, etc.).
Within each stroke element, there are three key pieces of information:
<skeleton> A list of x-y coordinates defining the skeleton which guide the contour in `points`. This tag can be blanked out if not necessary.</skeleton>
<points>A list of x-y coordinates defining the curve. These points define the path the stroke follows. And the values should be within 1 and {res}.</points>
<id>A short descriptive identifier for the stroke, explaining which part of the sketch it corresponds to.</id>
</strokes>
<layout>This element defines semantic groupings of strokes from `<strokes>` above. Each sub-element (e.g., <l1>, <l2>, ...) represents a meaningful part composed of multiple strokes.
<meaning>A short description of what the grouped strokes in following `<s_group>` represent.</meaning>
<s_group>A list of strokes tag which composing the semantical meaning. e.g.'s1,s2,s5'</s_group>
<rec>Two point coodinates which represent the top-left and bottom-right cornor of the rectangle</rec>
</layout>
</formatting>

"""

    if edit_mode == "add_only":
        mode_specific = """
The current mode is "Add Lines Only". This means you can only add new strokes to the canvas and cannot modify or delete existing strokes.
The <strokes> tag in your response should only contain the new strokes you want to add, not the entire canvas content.
Existing strokes will remain on the canvas, and the new strokes you add will be displayed along with them.

When the user selects an area and asks you to add something there, focus on adding new strokes within that selected area, keeping the rest of the drawing intact.

"""
    elif edit_mode == "edit_all":
        mode_specific = """
The current mode is "Modify existing strokes". This means you can completely redesign the content on the canvas.
The <strokes> tag in your response should contain the entire canvas content, including the existing strokes you want to keep and the new strokes you want to add.
The existing strokes will be completely replaced by your response, so if you want to keep some of the existing strokes, you must include them in your response.

When the user selects an area and asks you to modify it, you have two options:
1. If the user wants targeted changes only in that area: modify only the strokes in the selected area and keep all other strokes unchanged
2. If the user wants a complete redesign: replace all strokes with your new design

"""
    elif edit_mode == "edit_skeleton":
        mode_specific = """
If the user edits the `<skeleton>` of a stroke, you must generate a new corresponding `<points>` contour based on the updated skeleton.
The updated `<points>` must:
- Follow and wrap around the new skeleton to define the part's shape clearly.
- Preserve the connection between the part and neighboring parts when needed (e.g., an arm connected to the body).
- Only change the `<points>` of the edited stroke — keep its `<skeleton>` and <id> unchanged.
- Leave all other strokes completely unchanged if they are not involved.
You should create the new `<points>` to properly wrap around the new `<skeleton>`
, ensuring that the visual shape still reflects a natural limb or body part with clear thickness and rounded or angular volume as appropriate to the part.
However, not all parts need their `<points>` to form a closed, standalone shape.
For example, an arm or an ear usually grows out from the body — its starting and ending points should connect naturally to the body outline, not form a full closed loop by themselves.
When updating `<points>`, you must consider the meaning (semantics) of the part and how it fits with the surrounding strokes on the canvas.

Example:
Original stroke:
<s6>
    <skeleton>'x309y364', 'x345y393'</skeleton>
    <points>'x293y335', 'x337y364', 'x360y393', 'x339y409', 'x310y380'</points>
    <id>right arm</id>
</s6>
If the user modifies the skeleton to: <skeleton>'x309y364', 'x333y357', 'x355y207'</skeleton>
Then a reasonable updated points could be: <points>'x302y351', 'x325y343', 'x343y320', 'x365y317', 'x364y342', 'x342y366', 'x307y372'</points>
Notice: The arm's points do not form a fully closed loop by themselves — instead, they naturally connect back to the body's shape. Final updated stroke:
<update>
<s6>
    <skeleton>'x309y364', 'x333y357', 'x355y327'</skeleton>
    <points>'x302y351', 'x325y343', 'x343y320', 'x365y317', 'x364y342', 'x342y366', 'x307y372'</points>
    <id>right arm</id>
</s6>
</update>
Key principles:
- Fit the new points naturally to the new skeleton. The points should form a reasonably tight envelope around the skeleton path while still preserving the visual mass and thickness suitable for coloring book style.
- Respect how the part connects to other parts — don't force every part into an independent closed shape.
- Maintain a full and balanced figure when seen as a whole.
This ensures that after skeleton edits, the drawing remains natural, expressive, and consistent with the coloring book style.

"""
    elif edit_mode == "edit_layout":
        mode_specific = """
You are now in "Modify layout" mode. In this mode, you should move and scale the strokes based on the updated layout information, without changing the shape of the strokes. For each modified layout element, update the strokes listed in its s_group so that their new size and position fit within the new <rec> bounding box. Note: There is a layer order between layout elements. Elements with smaller IDs appear in front of those with larger IDs. If a stroke from a front element overlaps a stroke behind it, you need to adjust the back stroke to reflect the occlusion.

Here is a modification example:
original sketch:
<strokes>
<s1><skeleton></skeleton><points>'x171y226', 'x219y220', 'x272y246', 'x290y298', 'x281y335', 'x246y367', 'x207y371', 'x171y361', 'x136y315', 'x146y258', 'x171y227'</points><id>apple body</id></s1>
<s2><skeleton></skeleton><points>'x185y247', 'x209y261', 'x238y254'</points><id>apple stem</id></s2>
<s3><skeleton></skeleton><points>'x208y257', 'x216y220', 'x230y204', 'x249y193'</points><id>apple indentation</id></s3>
<s4><skeleton></skeleton><points>'x392y172', 'x403y169', 'x434y170', 'x440y173', 'x442y179', 'x430y184', 'x402y183', 'x391y178', 'x390y174', 'x393y172'</points><id>banana tip</id></s4>
<s5><skeleton></skeleton><points>'x409y183', 'x405y203', 'x388y225', 'x337y260', 'x305y280', 'x310y302', 'x350y308', 'x399y282', 'x437y235', 'x440y208', 'x438y185'</points><id>banana body outline</id></s5>
<s6><skeleton></skeleton><points>'x418y210', 'x371y257', 'x342y268'</points><id>banana ridge</id></s6>
</strokes>
<layout>
<l1><meaning>apple</meaning><s_group>s1, s2, s3</s_group><rec>'x133y192', 'x292y374'</rec></l1>
<l2><meaning>banana</meaning><s_group>s4, s5, s6</s_group><rec>'x302y167', 'x444y311'</rec></l2>
</layout>
The user modifies the <rec> of <l1> (apple) to: <rec>'x207y194', 'x334y342'</rec>. This causes <l1> to overlap part of the strokes in <l2> (banana). You need to: 1.Move and scale the strokes in <l1> to fit the new bounding box, 2.For the overlapped stroke <s5> in <l2>, split it into two parts: keep the visible head and tail, remove the hidden middle part. Give the two new strokes new IDs.
So the modification result is:
<strokes>
<s1><skeleton></skeleton><points>'x237y221', 'x275y216', 'x318y237', 'x332y278', 'x325y308', 'x297y334', 'x266y337', 'x237y329', 'x209y292', 'x217y246', 'x237y222'</points><id>apple body outline</id></s1>
<s2><skeleton></skeleton><points>'x248y238', 'x267y249', 'x290y243'</points><id>apple stem</id></s2>
<s3><skeleton></skeleton><points>'x266y246', 'x273y216', 'x284y203', 'x299y194'</points><id>apple indentation</id></s3>
<s4><skeleton></skeleton><points>'x392y172', 'x403y169', 'x434y170', 'x440y173', 'x442y179', 'x430y184', 'x402y183', 'x391y178', 'x390y174', 'x393y172'</points><id>banana tip</id></s4>
<s5><skeleton></skeleton><points>'x409y183', 'x405y203', 'x388y225', 'x337y260'</points><id>banana body outline 1</id></s5>
<s6><skeleton></skeleton><points>'x330y309', 'x350y308', 'x399y282', 'x437y235', 'x440y208', 'x438y185'</points><id>banana body outline 2</id></s6>
<s7><skeleton></skeleton><points>'x418y210', 'x371y257', 'x342y268'</points><id>banana ridge</id></s7>
</strokes>
<layout>
<l1><meaning>apple</meaning><s_group>s1, s2, s3</s_group><rec>'x207y194', 'x334y342'</rec></l1>
<l2><meaning>banana</meaning><s_group>s4, s5, s6, s7</s_group><rec>'x302y167', 'x444y311'</rec></l2>
</layout>
"""
    else:
        mode_specific = ""
        print(f"edit_mode={edit_mode}, mode_specific is blank")
    full_prompt = base_prompt + gt_example + selection_example + mode_specific
    
    return full_prompt