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

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

glyph-module

glyph-block Letter-Latin-Z : begin
	glyph-block-import CommonShapes
	glyph-block-import Common-Derivatives
	glyph-block-import Mark-Adjustment : ExtendBelowBaseAnchors
	glyph-block-import Letter-Shared : CreateAccentedComposition
	glyph-block-import Letter-Shared-Shapes : HCurlyTail PalatalHook RetroflexHook CyrDescender
	glyph-block-import Letter-Blackboard : BBS BBD
	glyph-block-import Letter-Latin-X : XStrand

	define MODE-Z      0
	define MODE-RTAIL  1
	define MODE-ZDESC  2
	define MODE-ZSWASH 3

	define [DisplayBottomStroke mode] : not : mode === MODE-ZDESC || mode === MODE-ZSWASH

	define [ZSerifless top] : glyph-proc

	define [ZStdSerifs top] : glyph-proc
		include : tagged 'serifLT' : VSerif.dl SB top VJut
		include : tagged 'serifRB' : VSerif.ur RightSB 0 VJut

	define [ZMotionSerifsB top] : glyph-proc
		include : tagged 'serifRB' : VSerif.ur RightSB 0 VJut

	define [ZMotionSerifsT top] : glyph-proc
		include : tagged 'serifLT' : VSerif.dl SB top VJut

	define [ZBaseShape mode] : glyph-proc
		local cor : 1.15 * HVContrast
		include : tagged 'strokeTop' : HBar.t SB RightSB CAP
		include : spiro-outline
			corner SB [if (mode === MODE-ZSWASH) 0 Stroke]
			corner (RightSB - Stroke * cor) (CAP - Stroke)
			corner RightSB (CAP - Stroke)
			corner (SB + Stroke * cor) [if (mode === MODE-ZSWASH) 0 Stroke]
		if [DisplayBottomStroke mode] : include : tagged 'strokeBottom' : HBar.b SB RightSB 0

	define [ZCurlyShape mode] : glyph-proc
		include : tagged 'strokeTop' : HBar.t SB (RightSB - [HSwToV Stroke]) CAP
		include : XStrand false SLAB SB 0 RightSB CAP 0.125 0.4 0.32
		if [DisplayBottomStroke mode] : include : tagged 'strokeBottom' : HBar.b (SB + [HSwToV Stroke]) RightSB 0

	define [HBar.mOver] : refer-glyph 'barOver'
	define [DBarOver] : refer-glyph 'antiSlashOver'

	define [SmallZBaseShape mode] : glyph-proc
		local cor : 1.2 * HVContrast
		include : tagged 'strokeTop' : HBar.t SB RightSB XH
		include : dispiro
			corner SB [if (mode === MODE-ZSWASH) 0 Stroke] [widths.rhs : VSwToH Stroke]
			corner RightSB (XH - Stroke)                   [widths.lhs : VSwToH Stroke]
		if [DisplayBottomStroke mode] : include : tagged 'strokeBottom' : HBar.b SB RightSB 0
		set-base-anchor "trailing" RightSB 0

	define [SmallZCurlyShape mode] : glyph-proc
		include : tagged 'strokeTop' : HBar.t SB (RightSB - [HSwToV Stroke]) XH
		include : XStrand false SLAB SB 0 RightSB XH 0.125 0.4 0.36
		if [DisplayBottomStroke mode] : include : tagged 'strokeBottom' : HBar.b (SB + [HSwToV Stroke]) RightSB 0
		set-base-anchor "trailing" RightSB 0

	define [ZCursiveShapeImpl top mode] : glyph-proc
		define hookTerminalWidth : AdviceStroke 3.5
		define xDiagWidth : 1 * Stroke
		define yFootHeight : [Math.max (0.15 * top) (Stroke * 0.625)] + 0.7 * Stroke
		define kFoot : 1 + HalfStroke / yFootHeight
		define yHookDepth : Hook + QuarterStroke
		define yHookStraightDepth : Math.min (yHookDepth - Stroke * 1.1) (yHookDepth / 3 - QuarterStroke)
		define xHookDepth : Math.max (0.25 * (RightSB - SB)) (hookTerminalWidth * 1.5)
		define xMockTailDepth : Math.max (0.375 * (RightSB - SB)) (hookTerminalWidth * 1.375)
		define kTop 0.625
		define kBot 0.625
		define yTailDepth : Hook * 0.5

		include : tagged 'strokeTop' : intersection
			spiro-outline
				corner SB 0
				corner (-Width) 0
				corner (-Width) (2 * top)
				corner (RightSB - xDiagWidth + TINY) (2 * top)
				corner (RightSB - xDiagWidth + TINY) (top - yFootHeight)
			dispiro
				flat (SB + OX) (top - yHookDepth) [widths.rhs.heading hookTerminalWidth Upward]
				curl (SB + OX) (top - yHookDepth + yHookStraightDepth) [heading Upward]
				arcvh
				g2.right.mid (SB + xHookDepth) (top - O) [widths.rhs.heading Stroke Rightward]
				flat [mix (SB + xMockTailDepth) RightSB kTop] (top - kTop * yTailDepth)
				curl RightSB                                  (top - yTailDepth)

		include : dispiro
			corner RightSB (top - yFootHeight)                 [widths.rhs : VSwToH Stroke]
			corner SB [if (mode == MODE-ZSWASH) 0 yFootHeight] [widths.lhs : VSwToH Stroke]

		include : VBar.r RightSB top (top - yFootHeight) [VSwToH xDiagWidth]
		if (mode != MODE-ZSWASH) : include : VBar.l SB 0 yFootHeight [VSwToH xDiagWidth]

		include : tagged 'strokeBottom' : match mode
			[Just MODE-RTAIL] : intersection
				spiro-outline
					corner (SB + xDiagWidth) yFootHeight
					corner (SB + xDiagWidth) (-top)
					corner (2 * Width) (-top)
					corner (2 * Width) (top)
					corner RightSB top

				union
					VBar.r RightSB 0 yHookDepth hookTerminalWidth
					dispiro
						flat  RightSB               O [widths.rhs.heading Stroke Leftward]
						g2  (RightSB - xHookDepth) O [widths.rhs.heading Stroke Leftward]
						flat [mix (RightSB - xHookDepth) SB kBot] (kBot * yTailDepth)
						curl SB                                   (yTailDepth)
			([Just MODE-ZDESC] || [Just MODE-ZSWASH]) : no-shape
			__ : intersection
				spiro-outline
					corner (SB + xDiagWidth - TINY) yFootHeight
					corner (SB + xDiagWidth - TINY) (-top)
					corner (2 * Width) (-top)
					corner (2 * Width) (top)
					corner RightSB top

				dispiro
					flat (RightSB - OX) yHookDepth [widths.rhs.heading hookTerminalWidth Downward]
					curl (RightSB - OX) (yHookDepth - yHookStraightDepth) [heading Downward]
					arcvh
					g2.left.mid (RightSB - xHookDepth) O [widths.rhs.heading Stroke Leftward]
					flat [mix (RightSB - xHookDepth) SB kBot] (kBot * yTailDepth)
					curl SB                                   (yTailDepth)

		if (mode != MODE-RTAIL) : begin
			set-base-anchor "trailing" (RightSB - 0.55 * xHookDepth) 0

	define [ZCursiveShape mode]         : ZCursiveShapeImpl CAP mode
	define [SmallZCursiveShape mode]    : ZCursiveShapeImpl XH mode

	define [NoBottomStrokeMask top] : glyph-proc
	define [CurlyBottomStrokeMask top] : spiro-outline
		corner 0 0
		corner SB 0
		corner (SB + Stroke) Stroke
		corner 0 Stroke

	define [DTailBottomStroke] : dispiro
		widths.lhs
		flat SB 0 [heading Rightward]
		curl (RightSB - HookX) 0
		archv
		straight.down.end RightSB (-Hook) [widths.heading 0 Stroke Downward]

	define [SwashBottomStroke] : dispiro
		widths.lhs
		g4 SB 0
		alsoThru 0.36 0.6 important
		flat (RightSB - 1) Descender
		curl RightSB Descender

	define [ZemlyaBottomStroke] : begin
		local fine : AdviceStroke 4
		local hx : [Math.max (0.5 * HookX) : HSwToV : 1.25 * fine] + [HSwToV : 0.125 * fine]
		return : dispiro
			widths.lhs
			flat SB 0 [heading Rightward]
			curl (RightSB - hx) 0
			archv
			g4.down.mid (RightSB - O - [HSwToV fine]) [mix (Descender + fine) 0 0.5] [widths.lhs.heading fine {.x HVContrast .y (-(fine - Stroke) / fine)}]
			arcvh
			g2.left.mid (RightSB - hx) (Descender + fine + O)
			alsoThru 0.5 0.5 [widths.center fine]
			g2.left.mid (SB + hx) ([mix Descender 0 0.75] - fine) [widths.rhs fine]
			archv
			g4.down.end (SB + O + [HSwToV fine]) Descender [heading Downward]

	define [ZemlyaBottomStrokeCursive] : begin
		local fine : AdviceStroke 4
		local hx : [Math.max (0.5 * HookX) : HSwToV : 1.25 * fine] + [HSwToV : 0.125 * fine]
		return : dispiro
			flat (RightSB - [HSwToV fine]) HalfStroke [widths.lhs.heading fine Downward]
			curl (RightSB - [HSwToV fine]) [mix (Descender + fine) 0 0.5] [widths.lhs.heading fine Downward]
			arcvh
			g2.left.mid (RightSB - hx) (Descender + fine + O)
			alsoThru 0.5 0.5 [widths.center fine]
			g2.left.mid (SB + hx) ([mix Descender 0 0.75] - fine) [widths.rhs fine]
			archv
			g4.down.end (SB + O + [HSwToV fine]) Descender [heading Downward]

	define ZConfig : SuffixCfg.weave
		object # Body
			straight  { ZBaseShape    SmallZBaseShape    NoBottomStrokeMask    }
			curly     { ZCurlyShape   SmallZCurlyShape   CurlyBottomStrokeMask }
			cursive   { ZCursiveShape SmallZCursiveShape NoBottomStrokeMask    }
		object # Serifs
			""            { ZSerifless     } # for Cursive
			serifless     { ZSerifless     }
			serifed       { ZStdSerifs     }
			bottomSerifed { ZMotionSerifsB }
			topSerifed    { ZMotionSerifsT }
		object # overlay
			""                     { null       }
			withCrossBar           { DBarOver   }
			withHorizontalCrossBar { HBar.mOver }

	foreach { suffix { {capital small bsMask} {serifs} {slash} } } [pairs-of ZConfig] : do
		create-glyph "Z.\(suffix)" : glyph-proc
			include : MarkSet.capital
			include : capital MODE-Z
			if serifs : include : serifs CAP
			if slash  : include : slash  CAP

		create-glyph "Z/rtailBase.\(suffix)" : glyph-proc
			include : MarkSet.capital
			include : capital MODE-RTAIL
			if serifs : include : serifs CAP
			if slash  : include : slash  CAP

		create-glyph "ZHookBottom.\(suffix)" : glyph-proc
			include : MarkSet.capDesc
			set-base-anchor 'overlay' Middle (CAP / 2)
			include : capital MODE-ZDESC
			if serifs : include : serifs CAP
			if slash  : include : slash  CAP
			eject-contour 'serifRB'
			include : difference [DTailBottomStroke] [bsMask CAP]

		create-glyph "cyrl/Zemlya.\(suffix)" : glyph-proc
			include : MarkSet.capital
			include : ExtendBelowBaseAnchors Descender
			if (capital === ZCursiveShape)
			: then : begin
				include : capital MODE-RTAIL
				if serifs : include : serifs CAP
				if slash  : include : slash  CAP
				include : ZemlyaBottomStrokeCursive
			: else : begin
				include : capital MODE-ZDESC
				if serifs : include : serifs CAP
				if slash  : include : slash  CAP
				eject-contour 'serifRB'
				include : difference [ZemlyaBottomStroke] [bsMask CAP]

		create-glyph "ZSwash.\(suffix)" : glyph-proc
			include : MarkSet.capDesc
			set-base-anchor 'overlay' Middle (CAP / 2)
			include : capital MODE-ZSWASH
			if serifs : include : serifs CAP
			if slash  : include : slash  CAP
			eject-contour 'serifRB'
			include : difference [SwashBottomStroke] [bsMask CAP]

		create-glyph "z.\(suffix)" : glyph-proc
			include : MarkSet.e
			include : small MODE-Z
			if serifs : include : serifs XH
			if slash  : include : slash  XH

		create-glyph "z/rtailBase.\(suffix)" : glyph-proc
			include : MarkSet.e
			include : small MODE-RTAIL
			if serifs : include : serifs XH
			if slash  : include : slash  XH

		create-glyph "zHookBottom.\(suffix)" : glyph-proc
			include : MarkSet.p
			set-base-anchor 'overlay' Middle (XH / 2)
			include : small MODE-ZDESC
			if serifs : include : serifs XH
			if slash  : include : slash  XH
			eject-contour 'serifRB'
			include : difference [DTailBottomStroke] [bsMask XH]

		create-glyph "cyrl/zemlya.\(suffix)" : glyph-proc
			include : MarkSet.e
			include : ExtendBelowBaseAnchors Descender
			if (small === SmallZCursiveShape)
			: then : begin
				include : small MODE-RTAIL
				if serifs : include : serifs XH
				if slash  : include : slash  XH
				include : ZemlyaBottomStrokeCursive
			: else : begin
				include : small MODE-ZDESC
				if serifs : include : serifs XH
				if slash  : include : slash  XH
				eject-contour 'serifRB'
				include : difference [ZemlyaBottomStroke] [bsMask XH]

		create-glyph "zSwash.\(suffix)" : glyph-proc
			include : MarkSet.p
			set-base-anchor 'overlay' Middle (XH / 2)
			include : small MODE-ZSWASH
			if serifs : include : serifs XH
			if slash  : include : slash  XH
			eject-contour 'serifRB'
			include : difference [SwashBottomStroke] [bsMask XH]

		create-glyph "zCurlyTail.\(suffix)" : glyph-proc
			include : MarkSet.e
			include : small MODE-ZDESC
			if serifs : include : serifs XH
			if slash  : include : slash  XH
			eject-contour 'serifRB'
			local fine : AdviceStroke2 5 4 XH
			local rinner : Math.max (XH * 0.04) (fine * 0.1)
			local x2 : mix (SB + Stroke) RightSB 0.3
			local x1 : mix x2 (RightSB - fine - rinner * 1.5) 0.45
			local y2 : -XH * 0.2
			local m1 : RightSB - fine / 2 - rinner * 1.5 + O
			include : difference
				HCurlyTail fine Stroke rinner SB m1 (RightSB + fine / 2) x1 x2 y2
				bsMask XH

	select-variant 'Z' 'Z'
	link-reduced-variant 'Z/sansSerif' 'Z' MathSansSerif
	link-reduced-variant 'Z/reduced' 'Z'
	link-reduced-variant 'Z/reduced/sansSerif' 'Z'
	select-variant 'Z/rtailBase' (follow -- 'Z')

	select-variant 'smcpZ' 0x1D22 (shapeFrom -- 'z') (follow -- 'Z')

	select-variant 'z' 'z'
	link-reduced-variant 'z/sansSerif' 'z' MathSansSerif
	link-reduced-variant 'z/reduced' 'z'
	select-variant 'z/rtailBase' (follow -- 'z')

	select-variant 'ZHookBottom' 0x224   (follow -- 'ZDesc')
	select-variant 'zHookBottom' 0x225   (follow -- 'zDesc')
	select-variant 'ZSwash'      0x2C7F  (follow -- 'ZDesc')
	select-variant 'zSwash'      0x240   (follow -- 'zDesc')
	select-variant 'zCurlyTail'  0x291   (follow -- 'zDesc')
	select-variant 'cyrl/Zemlya' 0xA640  (follow -- 'ZDesc')
	select-variant 'cyrl/zemlya' 0xA641  (follow -- 'zDesc')
	select-variant 'cyrl/Zemlya/reduced' (follow -- 'ZDesc/reduced') (shapeFrom -- 'cyrl/Zemlya')
	select-variant 'cyrl/zemlya/reduced' (follow -- 'zDesc/reduced') (shapeFrom -- 'cyrl/zemlya')

	select-variant 'z/phoneticRight'           (shapeFrom --'z')
	select-variant 'z/rtailBase/phoneticRight' (shapeFrom --'z/rtailBase') (follow -- 'z/phoneticRight')
	select-variant 'zCurlyTail/phoneticRight'  (shapeFrom --'zCurlyTail')  (follow -- 'zDesc/phoneticRight')

	derive-composites 'ZDesc'        0x2C6B 'Z/rtailBase' [CyrDescender.r RightSB 0]
	derive-composites 'zDesc'        0x2C6C 'z/rtailBase' [CyrDescender.r RightSB 0]

	derive-composites 'ZPalatalHook' 0xA7C6 'Z/rtailBase' [PalatalHook.r RightSB 0]
	derive-composites 'zPalatalHook' 0x1D8E 'z/rtailBase' [PalatalHook.r RightSB 0]

	derive-composites 'zRTail'       0x290  'z/rtailBase' [RetroflexHook.r RightSB 0]
	derive-composites 'zRTail/phoneticRight' null 'z/rtailBase/phoneticRight' [RetroflexHook.r RightSB 0]

	alias 'grek/Zeta' 0x396 'Z/reduced'
	alias-reduced-variant 'grek/Zeta/sansSerif' 'grek/Zeta' 'Z/reduced/sansSerif' MathSansSerif

	CreateAccentedComposition 'ZAcute' 0x179 'Z' 'acuteAbove'
	CreateAccentedComposition 'zAcute' 0x17A 'z' 'acuteAbove'
	CreateAccentedComposition 'ZDot'   0x17B 'Z' 'dotAbove'
	CreateAccentedComposition 'zDot'   0x17C 'z' 'dotAbove'
	CreateAccentedComposition 'ZCaron' 0x17D 'Z' 'caronAbove' true
	CreateAccentedComposition 'zCaron' 0x17E 'z' 'caronAbove' true

	alias 'Z.PLK' null 'Z/reduced'
	alias 'z.PLK' null 'z/reduced'
	CreateAccentedComposition 'ZAcute.PLK' null 'Z/reduced' 'kreskaAbove'
	CreateAccentedComposition 'zAcute.PLK' null 'z/reduced' 'kreskaAbove'
	CreateAccentedComposition 'ZDot.PLK'   null 'Z/reduced' 'kropkaAbove'
	CreateAccentedComposition 'zDot.PLK'   null 'z/reduced' 'kropkaAbove'

	CreateAccentedComposition 'ZStroke' 0x1B5 'Z/reduced' 'barOver'
	CreateAccentedComposition 'zStroke' 0x1B6 'z/reduced' 'barOver'

	CreateAccentedComposition 'cyrl/Dzelo' 0xA642 'cyrl/Zemlya/reduced' 'barOver'
	CreateAccentedComposition 'cyrl/dzelo' 0xA643 'cyrl/zemlya/reduced' 'barOver'

	define [BBZShape top] : glyph-proc
		include : HBar.t SB RightSB top BBS
		include : HBar.b SB RightSB 0 BBS
		include : intersection
			Rect top 0 SB RightSB
			union
				dispiro
					widths.center BBS
					corner SB (BBS / 2)
					corner (RightSB - BBD) (top - BBS / 2)
				dispiro
					widths.center BBS
					corner (SB + BBD) (BBS / 2)
					corner RightSB (top - (BBS / 2))

		include : intersection
			union
				VBar.r RightSB (top - BBS * 2) top BBS
				VBar.l  SB 0 (BBS * 2) BBS
			spiro-outline
				corner SB (BBS / 2)
				corner (RightSB - BBD) (top - BBS / 2)
				corner RightSB (top - (BBS / 2))
				corner (SB + BBD) (BBS / 2)

	create-glyph 'mathbb/Z' 0x2124  : composite-proc [MarkSet.capital] [BBZShape CAP]
	create-glyph 'mathbb/z' 0x1D56B : composite-proc [MarkSet.e] [BBZShape XH]
