-- Emulate a quickcheck import; deriveArbitrary works on any type with the
-- right name and kind
data Gen a

data Obj
  = Square Int Int
  | Circle Int
  | Polygon [(Int, Int)]
  | Rotate2 Double Obj
  | Empty
  | Full
  | Complement Obj
  | UnionR Double [Obj]
  | DifferenceR Double Obj [Obj]
  | IntersectR Double [Obj]
  | Translate Double Double Obj
  | Scale Double Double Obj
  | Mirror Double Double Obj
  | Outset Double Obj
  | Shell Double Obj
  | WithRounding Double Obj


arbitrary :: Gen Obj
arbitrary
  = let
      terminal
        = [(Square <$> arbitrary) <*> arbitrary, Circle <$> arbitrary,
           Polygon <$> arbitrary, pure Empty, pure Full]
    in
      sized
        $ (\ n
             -> case n <= 1 of
                  True -> oneof terminal
                  False
                    -> oneof
                         $ ([(Rotate2 <$> arbitrary) <*> scale (subtract 1) arbitrary,
                             Complement <$> scale (subtract 1) arbitrary,
                             (UnionR <$> arbitrary) <*> scale (subtract 1) arbitrary,
                             ((DifferenceR <$> arbitrary) <*> scale (flip div 2) arbitrary)
                               <*> scale (flip div 2) arbitrary,
                             (IntersectR <$> arbitrary) <*> scale (subtract 1) arbitrary,
                             ((Translate <$> arbitrary) <*> arbitrary)
                               <*> scale (subtract 1) arbitrary,
                             ((Scale <$> arbitrary) <*> arbitrary)
                               <*> scale (subtract 1) arbitrary,
                             ((Mirror <$> arbitrary) <*> arbitrary)
                               <*> scale (subtract 1) arbitrary,
                             (Outset <$> arbitrary) <*> scale (subtract 1) arbitrary,
                             (Shell <$> arbitrary) <*> scale (subtract 1) arbitrary,
                             (WithRounding <$> arbitrary) <*> scale (subtract 1) arbitrary]
                              <> terminal))