$$include '../../meta/macros.ptl'

import [mix linreg clamp fallback] from "@iosevka/util"
import [MathSansSerif] from "@iosevka/glyph/relation"

glyph-module

glyph-block Letter-Latin-X : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Letter-Shared-Shapes : SerifFrame WithSerifOverflowMask
	glyph-block-import Letter-Shared-Shapes : DiagTail
	glyph-block-import Letter-Shared-Shapes : CyrDescender PalatalHook

	glyph-block-export HalfXStrand
	define [HalfXStrand stb fSlab _xOuter yOuter xCenter yCenter turn pStraight tension _sw _pConn] : glyph-proc
		local sw : fallback _sw Stroke
		local sbCor : if stb ([StrokeWidthBlend 1 6] * OX * ([Math.abs (yOuter - yCenter)] / CAP)) 0
		local xOuter : _xOuter + ([HSwToV : 0.5 * sw] + [Math.max (-SideJut) sbCor]) * [if (xCenter > _xOuter) 1 (-1)]

		if stb : begin
			local hst : (0.5 * sw) * [DiagCor (yCenter - yOuter) (xCenter - xOuter) 0 0]
			local hse : (0.5 * sw) * [Math.min 0.97 ([AdviceStroke 3] / Stroke)]
			local xOuterAdjusted : _xOuter + ([HSwToV hst] + [Math.max (-SideJut) sbCor]) * [if (xCenter > _xOuter) 1 (-1)]
			include : dispiro
				corner xOuterAdjusted yOuter [widths.heading hst hst [if (yOuter < yCenter) Upward Downward]]
				corner xCenter yCenter [widths.center : 2 * hse]

		: else : begin
			local height : Math.abs (yOuter - yCenter)
			local slabClearance : if fSlab ((sw / Stroke) * [AdviceStroke2 2 3 height]) 0
			local turnyOuter : mix yOuter yCenter [if fSlab [Math.max turn (slabClearance / height)] turn]
			local cyOuter : mix turnyOuter yCenter tension
			local straightXOuter : mix xOuter xCenter pStraight
			local straightYOuter : mix cyOuter yCenter pStraight
			local xCenterAdj : mix xCenter xOuter [fallback _pConn 0]
			local yCenterAdj : mix yCenter cyOuter [fallback _pConn 0]
			include : dispiro
				widths.center sw
				flat xOuter yOuter [heading [if (yOuter < yCenter) Upward Downward]]
				curl xOuter turnyOuter [heading [if (yOuter < yCenter) Upward Downward]]
				quadControls 0 ((cyOuter - turnyOuter) / (straightYOuter - turnyOuter)) 24
				flat straightXOuter straightYOuter
				curl xCenterAdj yCenterAdj

	glyph-block-export XStrand
	define [XStrand stb slab xLeft yLeft xRight yRight turn pStraight tension _sw] : glyph-proc
		local xMid : mix xLeft xRight 0.5
		local yMid : mix yLeft yRight 0.5

		include : HalfXStrand stb slab xLeft yLeft xMid yMid turn pStraight tension _sw (-0.001)
		include : HalfXStrand stb slab xRight yRight xMid yMid turn pStraight tension _sw (-0.001)

	define [XChanceryStrand sign fSlab leftX leftY rightX rightY fHalf _sw] : begin
		local sw : fallback _sw Stroke
		local blendK1X : StrokeWidthBlend 0.58 0.65
		local blendK1Y   0.2
		local blendK2X   0.78
		local blendK2Y : StrokeWidthBlend 0.5 0.4

		local pStraightX : StrokeWidthBlend 0.3 0.35
		local pStraightY : StrokeWidthBlend 0.2 0.25

		local fine : [AdviceStroke 3] * (sw / Stroke)

		return : dispiro
			if fHalf
				flat [mix leftX rightX 0.5] [mix leftY rightY 0.5] [widths.center fine]
				list
					flat (leftX - [if fSlab SideJut 0]) (leftY - sign * sw / 2) [widths.center.heading sw Rightward]
					curl (leftX + TINY) (leftY - sign * sw / 2) [widths.center.heading sw Rightward]
					alsoThruThem {{blendK1X blendK1Y} {blendK2X blendK2Y}}
					flat [mix leftX rightX pStraightX] [mix leftY rightY pStraightY] [widths.center : mix sw fine 0.5]
					corner [mix leftX rightX 0.5] [mix leftY rightY 0.5] [widths.center fine]
			curl [mix leftX rightX (1 - pStraightX)] [mix leftY rightY (1 - pStraightY)] [widths.center : mix sw fine 0.5]
			alsoThruThem {{(1 - blendK2X) (1 - blendK2Y)} {(1 - blendK1X) (1 - blendK1Y)}}
			flat (rightX - TINY) (rightY + sign * sw / 2) [widths.center.heading sw Rightward]
			curl (rightX + [if fSlab SideJut 0]) (rightY + sign * sw / 2) [widths.center.heading sw Rightward]

	glyph-block-export XCursiveHalfShape
	define [XCursiveHalfShape] : with-params [
			top bottom left right
			[swMid   : AdviceStroke 2.75]
			[swEnd   : AdviceStroke 3]
			[swCoEnd : AdviceStroke 2]
			[setMark false] [flatTail false]
		] : glyph-proc
		local ada : ArchDepthAOf (ArchDepth * 0.8) (Width / 2)
		local adb : ArchDepthBOf (ArchDepth * 0.8) (Width / 2)
		local adws : (right - left) / (RightSB - Middle)
		local divHook : Math.min adws 1

		local fineMid : 0.55 * swMid
		local xMidBarRightEdge : left + [HSwToV swMid] / 2
		local xUpperTurn : mix (right - [HSwToV swEnd]) xMidBarRightEdge 0.5
		local upperHookDepth : Math.max (swEnd * 2) ([Math.sqrt divHook] * (Hook + swEnd * 0.125))
		local upperHookStraightDepth : Math.min
			upperHookDepth - swEnd * 1.125
			Math.max 1 : upperHookDepth / 5 - swEnd / 4
		local upperHalf : include : dispiro
			flat (xMidBarRightEdge - [HSwToV fineMid]) ([mix bottom top 0.5] + O) [widths.rhs.heading fineMid Upward]
			curl (xMidBarRightEdge - [HSwToV fineMid]) (top - ada)
			arch.rhs top (sw -- swEnd) (swBefore -- fineMid)
			flat (right - OX) (top - upperHookDepth + upperHookStraightDepth) [heading Downward]
			curl (right - OX) (top - upperHookDepth) [heading Downward]

		local rIn : Math.max [AdviceStroke 16] (0.4 * (right - left) - [HSwToV : 0.5 * swMid])
		local flatHookDepth : 1.3 * (right - left) - (0.5 - TanSlope) * swEnd - 1.5 * (rIn + 0.5 * swMid)
		local lowerHalf : include : if flatTail
			dispiro
				flat (xMidBarRightEdge - [HSwToV fineMid]) ([mix bottom top 0.5] - O) [widths.lhs fineMid]
				curl (xMidBarRightEdge - [HSwToV fineMid]) (bottom + [Math.min adb (swMid + rIn)])
				arcvh
				flat (xMidBarRightEdge + adws * (0.5 * swMid + rIn) + 0.25 * TanSlope * (0.5 * swMid + rIn)) bottom [widths.lhs.heading swCoEnd Rightward]
				curl right bottom
			dispiro
				flat (xMidBarRightEdge - [HSwToV : 0.5 * fineMid]) ([mix bottom top 0.5] - O) [widths.center fineMid]
				curl (xMidBarRightEdge - [HSwToV : 0.5 * fineMid]) (bottom + [Math.min adb (swMid + rIn)])
				arcvh 16
				DiagTail.F 1 (xMidBarRightEdge - [HSwToV : 0.5 * swCoEnd] + TanSlope * rIn) bottom rIn 50 flatHookDepth swCoEnd

		if setMark : begin
			define lowerHalfLastKnot lowerHalf.rhsKnots.(lowerHalf.rhsKnots.length - 1)
			set-base-anchor 'cyrlDescenderAttach' lowerHalfLastKnot.x lowerHalfLastKnot.y

	define STROKE-STRAIGHT     0
	define STROKE-CURLY        1
	define STROKE-CHANCERY     2
	define STROKE-CURSIVE      3
	define STROKE-CURSIVE-FLAT 4

	glyph-block-export XLetterForm
	define [XLetterForm] : with-params [
			df top bot
			stroke1 stroke2
			turn tension
			[sw df.mvs]
			[swCursiveMid   : (sw / Stroke) * [AdviceStroke 2.75]]
			[swCursiveEnd   : (sw / Stroke) * [AdviceStroke 3]]
			[swCursiveCoEnd : (sw / Stroke) * [AdviceStroke 2]]
		] : namespace
		local sw df.mvs
		export : define [base fSlab] : glyph-proc
			include : match stroke1
				[Just STROKE-STRAIGHT] : XStrand true  fSlab df.leftSB bot df.rightSB top turn 0.4 tension sw
				[Just STROKE-CURLY]    : XStrand false fSlab df.leftSB bot df.rightSB top turn 0.4 tension sw
				[Just STROKE-CHANCERY] : XChanceryStrand (-1) fSlab df.leftSB bot df.rightSB top false sw
				([Just STROKE-CURSIVE] || [Just STROKE-CURSIVE-FLAT]) : composite-proc
					XCursiveHalfShape top bot df.middle df.rightSB
						swCoEnd -- swCursiveCoEnd
						swEnd -- swCursiveEnd
						swMid -- swCursiveMid
						flatTail -- (stroke1 === STROKE-CURSIVE-FLAT)
					FlipAround df.middle [mix bot top 0.5]
				__ : glyph-proc
			include : match stroke2
				[Just STROKE-STRAIGHT] : XStrand true  fSlab df.leftSB top df.rightSB bot turn 0.4 tension sw
				[Just STROKE-CURLY]    : XStrand false fSlab df.leftSB top df.rightSB bot turn 0.4 tension sw
				[Just STROKE-CHANCERY] : XChanceryStrand (+1) fSlab df.leftSB top df.rightSB bot false sw
				[Just STROKE-CURSIVE]  : XCursiveHalfShape top bot df.middle df.rightSB
					swCoEnd -- swCursiveCoEnd
					swEnd -- swCursiveEnd
					swMid -- swCursiveMid
					setMark -- true
				__ : glyph-proc

		export : define [rightHalf fSlab] : glyph-proc
			local midy : mix top bot 0.5

			include : match stroke1
				[Just STROKE-STRAIGHT] : HalfXStrand true  fSlab df.rightSB top df.middle midy turn 0.4 tension sw
				[Just STROKE-CURLY]    : HalfXStrand false fSlab df.rightSB top df.middle midy turn 0.4 tension sw
				[Just STROKE-CHANCERY] : XChanceryStrand (-1) fSlab df.leftSB bot df.rightSB top true sw
				__ : glyph-proc
			include : match stroke2
				[Just STROKE-STRAIGHT] : HalfXStrand true  fSlab df.rightSB bot df.middle midy turn 0.4 tension sw
				[Just STROKE-CURLY]    : HalfXStrand false fSlab df.rightSB bot df.middle midy turn 0.4 tension sw
				[Just STROKE-CHANCERY] : XChanceryStrand (+1) fSlab df.leftSB top df.rightSB bot true sw
				[Just STROKE-CURSIVE]  : XCursiveHalfShape top bot df.middle df.rightSB
					swCoEnd -- swCursiveCoEnd
					swEnd -- swCursiveEnd
					swMid -- swCursiveMid
					setMark -- true
				__ : glyph-proc

	glyph-block-export XSerifs
	define XSerifs : namespace
		export : define [Full sf]             : composite-proc sf.lt.full sf.rt.full sf.lb.full sf.rb.full
		export : define [SemiChancery sf]     : composite-proc sf.rt.full sf.lb.full
		export : define [UnilateralMotion sf] : composite-proc sf.lt.outer
		export : define [BilateralMotion sf]  : composite-proc sf.lt.outer sf.rb.outer
		export : define [GrekLowerChi sf]     : composite-proc sf.lt.outer sf.rt.full sf.lb.full sf.rb.outer

	glyph-block-export XConfig
	define XConfig : object
		straightSerifless               { STROKE-STRAIGHT STROKE-STRAIGHT null                     false }
		curlySerifless                  { STROKE-CURLY    STROKE-CURLY    null                     false }
		cursive                         { STROKE-CURSIVE  STROKE-CURSIVE  null                     false }
		semiChanceryStraightSerifless   { STROKE-STRAIGHT STROKE-CHANCERY null                     false }
		semiChanceryCurlySerifless      { STROKE-CURLY    STROKE-CHANCERY null                     false }
		chancery                        { STROKE-CHANCERY STROKE-CHANCERY null                     false }
		straightSerifed                 { STROKE-STRAIGHT STROKE-STRAIGHT XSerifs.Full             true  }
		curlySerifed                    { STROKE-CURLY    STROKE-CURLY    XSerifs.Full             true  }
		semiChanceryStraightSerifed     { STROKE-STRAIGHT STROKE-CHANCERY XSerifs.SemiChancery     true  }
		semiChanceryCurlySerifed        { STROKE-CURLY    STROKE-CHANCERY XSerifs.SemiChancery     true  }
		straightUnilateralMotionSerifed { STROKE-STRAIGHT STROKE-STRAIGHT XSerifs.UnilateralMotion false }
		curlyUnilateralMotionSerifed    { STROKE-CURLY    STROKE-CURLY    XSerifs.UnilateralMotion false }
		straightBilateralMotionSerifed  { STROKE-STRAIGHT STROKE-STRAIGHT XSerifs.BilateralMotion  false }
		curlyBilateralMotionSerifed     { STROKE-CURLY    STROKE-CURLY    XSerifs.BilateralMotion  false }
		straightGrekLowerChiSerifed     { STROKE-STRAIGHT STROKE-STRAIGHT XSerifs.GrekLowerChi     true  }
		curlyGrekLowerChiSerifed        { STROKE-CURLY    STROKE-CURLY    XSerifs.GrekLowerChi     true  }

	foreach { suffix {stroke1 stroke2 serifShape fMaskBase} } [Object.entries XConfig] : do
		define [letterShape top bot turn tension] : glyph-proc
			local df : DivFrame 1 2
			local lf : XLetterForm df top bot stroke1 stroke2 turn tension
			include : WithSerifOverflowMask fMaskBase top bot df.leftSB df.rightSB : lf.base fMaskBase
			if serifShape : begin
				local sf : SerifFrame.fromDf df top bot
				include : serifShape sf

		create-glyph "X.\(suffix)" : glyph-proc
			include : MarkSet.capital
			include : letterShape CAP 0 0.1 0.28

		create-glyph "x.\(suffix)" : glyph-proc
			include : MarkSet.e
			include : letterShape XH 0 0.1 0.20

		create-glyph "latn/chi.\(suffix)" : glyph-proc
			include : MarkSet.p
			include : letterShape XH Descender 0.1 0.20

		create-glyph "latn/Chi.\(suffix)" : glyph-proc
			include : MarkSet.capDesc
			include : letterShape CAP Descender 0.1 0.20

	select-variant 'X' 'X'
	link-reduced-variant 'X/sansSerif' 'X' MathSansSerif
	alias 'grek/Chi' 0x3A7 'X'
	alias-reduced-variant 'grek/Chi/sansSerif' 'grek/Chi' 'X/sansSerif' MathSansSerif
	alias 'cyrl/Kha' 0x425 'X'

	select-variant 'x' 'x'
	link-reduced-variant 'x/sansSerif' 'x' MathSansSerif
	alias 'cyrl/kha' 0x445 'x'

	select-variant 'cyrl/Kha/descBase' (shapeFrom -- 'X') (follow -- 'X/descBase')
	select-variant 'cyrl/kha/descBase' (shapeFrom -- 'x') (follow -- 'x/descBase')

	select-variant 'grek/chi' 0x3C7 (shapeFrom -- 'latn/chi')
	link-reduced-variant 'grek/chi/sansSerif' 'grek/chi' MathSansSerif (shapeFrom -- 'latn/chi')
	select-variant 'latn/chi' 0xAB53 (follow -- 'x')
	select-variant 'latn/Chi' 0xA7B3 (follow -- 'X')

	select-variant 'smcpX' (shapeFrom -- 'x') (follow -- 'X')

	define [AddDescender Ctor] : function [src sel] : glyph-proc
		include [refer-glyph src] AS_BASE ALSO_METRICS
		local attachAnchor currentGlyph.baseAnchors.cyrlDescenderAttach
		if attachAnchor
		: then : begin
			local attach : currentGlyph.gizmo.unapply attachAnchor
			include : Ctor.r attach.x 0 (yAttach -- attach.y)
		: else : begin
			local sw : Ctor.Sw Stroke
			include : Ctor.r
				x -- RightSB + SideJut + sw * TanSlope
				y -- 0
				xLink -- RightSB - [HSwToV HalfStroke]

	derive-glyphs 'cyrl/KhaDescender' 0x4B2 'cyrl/Kha/descBase' [AddDescender CyrDescender]
	derive-glyphs 'cyrl/khaDescender' 0x4B3 'cyrl/kha/descBase' [AddDescender CyrDescender]
	derive-glyphs 'cyrl/KhaHook'      0x4FC 'cyrl/Kha/descBase' [AddDescender PalatalHook]
	derive-glyphs 'cyrl/khaHook'      0x4FD 'cyrl/kha/descBase' [AddDescender PalatalHook]
	alias 'xPalatalHook' 0x1D8D 'cyrl/khaHook'

	define [CyrlKhaBarShape top] : HOverlayBar [mix SB RightSB 0.08] [mix SB RightSB 0.92] (top / 2)
	derive-composites 'cyrl/KhaBar' 0x4FE 'cyrl/Kha' [CyrlKhaBarShape CAP]
	derive-composites 'cyrl/khaBar' 0x4FF 'cyrl/kha' [CyrlKhaBarShape XH]

	glyph-block-import Letter-Blackboard : BBS BBD
	define [BBXShape l r top] : let [kDiag : DiagCorDs top (r - l) BBD] : union
		intersection
			Rect top 0 (-Width) (Width * 2)
			union
				ExtLineCenter 1 BBS l top (r - kDiag * BBD) 0
				ExtLineCenter 1 BBS (l + kDiag * BBD) top r 0
		HBar.t    l (l + kDiag * BBD) top BBS
		HBar.b r (r - kDiag * BBD) 0 BBS
		intersection
			Rect top 0 (-Width) (Width * 2)
			difference
				ExtLineCenter 1 BBS l 0 r top
				spiro-outline
					corner l top
					corner (l + kDiag * BBD) top
					corner r 0
					corner (r - kDiag * BBD) 0

	create-glyph 'mathbb/X' 0x1D54F : composite-proc [MarkSet.capital] [BBXShape SB RightSB CAP]
	create-glyph 'mathbb/x' 0x1D569 : composite-proc [MarkSet.e]       [BBXShape SB RightSB XH]
