{- CSci 450/503: Org. of Programming Languages, MovableObjects Module
   Movable Objects Case Study from Thompson textbook
   H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2017-10-28: Adapt original from Thompson Sec. 4.6
2017-10-31: Factor original into 3 modules, including this one

Adapted from Chapter 14, Section 6, of:
    Simon Thompson.
    Haskell: The Craft of Functional Programming, Third Edition
    Addison-Wesley, 1996-2011.

Class laws for Movable?

- The location of a Movable object must be described with some
  collection of rectangular-coordinates (x,y) on the plane

Question: Are empty or infinite collections acceptable?

Points of interest in code:

*1* Class(..) export class name and all methods.  Otherwise give list
    of methods. Leave off () to only export class.
*2* Data(..) export type and all constructors.  Otherwise give
    list. Leave off () to only export type.
*3* Default definition of method
*4* Override method definition
*5* Use default method definition

-}

module MovableObjects
  ( Movable(..)  -- *1* export class and all methods
  , Vector(..)   -- *2* export data type and all constructors
  , Point(..)    -- *2* export data type and all constructors
  , Figure(..)   -- *2* export data type and all constructors
  )
where

{- MOVABLE OBJECTS -}

-- Displacement in 2-space
data Vector = Vector Float Float
              deriving Show

-- Point object in 2-space
data Point  = Point Float Float  -- rectangular coordinates on plane
              deriving Show

-- Figure object in 2-space
data Figure = Line Point Point   -- two points on line
            | Circle Point Float -- center, radius
              deriving Show

-- Type class for objects movable in 2-space
class Movable a where
    move      :: Vector -> a -> a
    reflectX  :: a -> a             -- reflect on x-axis
    reflectY  :: a -> a             -- relfect on y-axis
    rotate180 :: a -> a             -- relflect on both axes
    rotate180 = reflectX . reflectY -- *3* default definition

-- Make Point Movable
instance Movable Point where
    move (Vector v1 v2) (Point c1 c2) = Point (c1+v1) (c2+v2)
    reflectX (Point c1 c2)  = Point c1 (-c2)
    reflectY (Point c1 c2)  = Point (-c1) c2
    rotate180 (Point c1 c2) = Point (-c1) (-c2) -- *4* override

-- Make Figure Movable
instance Movable Figure where
    move v (Line p1 p2) = Line (move v p1) (move v p2)
    move v (Circle p r) = Circle (move v p) r

    reflectX (Line p1 p2) = Line (reflectX p1) (reflectX p2)
    reflectX (Circle p r) = Circle (reflectX p) r

    reflectY (Line p1 p2) = Line (reflectY p1) (reflectY p2)
    reflectY (Circle p r) = Circle (reflectY p) r

    -- *5* reflect180 for Figure uses default
