def __init__(self):
     self.text = Text(root)
     self.wheel = BicycleWheel()
     self.OFFSET = 4
     self.MAXSIZE = 250 
 def setUp(self):
     self.bicycleWheel = BicycleWheel()
class BicycleWheelGUI():
    def __init__(self):
        self.text = Text(root)
        self.wheel = BicycleWheel()
        self.OFFSET = 4
        self.MAXSIZE = 250 
          
    def getWheelCenter(self):
        return self.wheel.wheelSize + self.OFFSET    
        
    def drawCircle(self, radius):
        self.canvas.create_oval( self.getWheelCenter() - radius, self.getWheelCenter() - radius, self.getWheelCenter() + radius, self.getWheelCenter() + radius)
    
    def drawSpokes(self, numberOfSpokes, listOfSpokes):
        for i in range(numberOfSpokes):
            self.canvas.create_line(listOfSpokes[i][0] + self.OFFSET, listOfSpokes[i][1]+ self.OFFSET, listOfSpokes[i][2]+ self.OFFSET, listOfSpokes[i][3]+ self.OFFSET)
    
    def createWheelSlider(self):
        self.newWheelSlider = Scale( self.menuFrame, from_ = int(self.wheel.getMinWheelSizeAllowance()), to = self.MAXSIZE, orient = HORIZONTAL, label = "Wheel Radius:", command = self.onUpdateWheelSlider, tickinterval = (self.MAXSIZE - self.wheel.getMinWheelSizeAllowance())/5, length = 250)
        self.newWheelSlider.set(self.wheel.wheelSize)
        self.newWheelSlider.grid(row = 0, column = 0)
    
    def createHubSlider(self):
        self.newHubSlider = Scale(self.menuFrame, from_ = 0, to = int(self.wheel.getMaxHubSizeAllowance()), orient = HORIZONTAL, label = "Hub Radius:", resolution = 0.05, command = self.onUpdateWheelHubSlider, tickinterval = self.wheel.getMaxHubSizeAllowance()/5, length = 250)
        self.newHubSlider.set(self.wheel.hubSize)
        self.newHubSlider.grid(row = 1, column = 0)
    
    def createSpokesSlider(self):
        self.newSpokesSlider  = Scale(self.menuFrame, from_ = self.wheel.MIN_SPOKES, to = self.MAXSIZE, orient = HORIZONTAL, label = "Number Of Spokes:", command = self.onUpdateWheelNumberOfSpokes, tickinterval = self.MAXSIZE/5, length = 250)
        self.newSpokesSlider.set(self.wheel.numberOfSpokes)
        self.newSpokesSlider.grid(row = 2, column =0)
        
    def createMenuFrame(self):
        self.menuFrame = Frame(root)
        self.menuFrame.pack(side = "right")
        
    def createMenu(self):
        self.createWheelSlider()
        self.createHubSlider() 
        self.createSpokesSlider()  
        
        self.save = Button(self.menuFrame,text = 'Save', command = self.onSave)
        self.save.grid(row = 4, column = 0)
        
        self.load = Button(self.menuFrame,text = 'Load', command = self.onLoad)
        self.load.grid(row = 5, column = 0)

    def clearCanvas(self):
        self.canvas.delete("all")
        
    def createWheelFrame(self):
        self.wheelFrame  = Frame(root)
        self.wheelFrame.pack(side = 'left', expand  = True)
        self.canvas = Canvas(self.wheelFrame, bg ="white", width = 2*(self.MAXSIZE+self.OFFSET), height = 2*(self.MAXSIZE+self.OFFSET))
        self.canvas.pack()
    
    def drawWheel(self):
        self.drawCircle(self.wheel.wheelSize)
        self.drawCircle(self.wheel.hubSize)
        self.drawSpokes(self.wheel.numberOfSpokes, self.wheel.getPositionOfSpokes())

    def onUpdateWheelSlider(self, wheelSize):
        if float(wheelSize) != self.wheel.wheelSize:
            self.wheel.setWheelSize(float(wheelSize))
            self.updateWheel()
            self.createHubSlider()
            
    def onUpdateWheelHubSlider(self, hubSize):   
        if float(hubSize) != self.wheel.hubSize:
            self.wheel.setHubSize(float(hubSize))
            self.updateWheel()
            self.createWheelSlider()
            
    def onUpdateWheelNumberOfSpokes(self, numberOfSpokes):
        self.wheel.setNumberOfSpokes(int(numberOfSpokes))
        self.updateWheel()
            
    def updateWheel(self):
        self.clearCanvas()
        self.drawWheel()
 
    def onSave(self):
        self.wheel.saveFile(self.wheel.FILE_PATH)
       
    def onLoad(self):
        self.wheel.loadFile(self.wheel.FILE_PATH)
        self.updateWheel()
        self.createMenu()
    
    def onCreate(self):
        self.createWheelFrame()        
        self.drawWheel()
        self.createMenuFrame()
        self.createMenu()
        root.mainloop()
class BicycleWheelTest(unittest.TestCase):
    def setUp(self):
        self.bicycleWheel = BicycleWheel()
        
    def test_canary(self):
        self.assertTrue(True)
    
    def test_set_wheel_size_when_hub_size_is_less_than_one_forth_new_wheel_size(self):
        self.bicycleWheel.setWheelSize(100.0)
        self.assertEqual(100.0, self.bicycleWheel.wheelSize)
        
    def test_set_wheel_size_when_hub_size_is_equal_to_one_forth_new_wheel_size(self):
        self.bicycleWheel.setWheelSize(40.0)
        self.assertEqual(40.0, self.bicycleWheel.wheelSize)
        
    def test_set_wheel_size_when_hub_size_is_greater_than_one_forth_new_wheel_size(self):
        self.bicycleWheel.setWheelSize(30.0)
        self.assertEqual(80.0, self.bicycleWheel.wheelSize)
        
    def test_set_hub_size_when_new_hub_size_is_less_than_one_forth_wheel_size(self):
        self.bicycleWheel.setHubSize(10.5)
        self.assertEqual(10.5, self.bicycleWheel.hubSize)
        
    def test_set_hub_size_when_new_hub_size_is_equal_to_one_forth_wheel_size(self):
        self.bicycleWheel.setHubSize(20.0)
        self.assertEqual(20.0, self.bicycleWheel.hubSize)
        
    def test_set_hub_size_when_new_hub_size_is_greater_than_one_forth_wheel_size(self):
        self.bicycleWheel.setHubSize(30.0)
        self.assertEqual(10.0, self.bicycleWheel.hubSize)
        
    def test_set_number_of_spokes_when_new_number_of_spoke_is_greater_or_equal_to_8(self):
        self.bicycleWheel.setNumberOfSpokes(10)
        self.assertEqual(10, self.bicycleWheel.numberOfSpokes)
        
    def test_set_number_of_spokes_when_new_number_of_spoke_is_less_than_to_8(self):
        self.bicycleWheel.setNumberOfSpokes(6)
        self.assertEqual(8, self.bicycleWheel.numberOfSpokes)
    
    def test_get_angle_of_spokes_that_number_of_spokes_is_8(self):
        self.assertEqual(math.pi/4, self.bicycleWheel.getAngleOfSpokes())
        
    def test_get_angle_of_spokes_that_number_of_spokes_is_10(self):
        self.bicycleWheel.setNumberOfSpokes(10)
        self.assertEqual(math.pi/5, self.bicycleWheel.getAngleOfSpokes())

    def test_get_position_of_spokes_at_1st_spoke_when_number_of_spokes_is_8(self):
        positionList = self.bicycleWheel.getPositionOfSpokes()
        self.assertEqual([160.0, 80.0, 90.0, 80.0], positionList[0])
              
    def test_get_position_of_spokes_at_3rd_spoke_when_number_of_spokes_is_8(self):
        positionList = self.bicycleWheel.getPositionOfSpokes()
        self.assertEqual([80.0, 0.0, 80.0, 70.0], positionList[2])
    
    def test_load_invalid_file(self):
        self.assertRaises(IOError, self.bicycleWheel.loadFile('invalid.txt'))
        
    def test_load_file_from_previous_save_with_valid_input(self):
        self.bicycleWheel.setWheelSize(100.0)
        self.bicycleWheel.setHubSize(10.0)
        self.bicycleWheel.setNumberOfSpokes(12)
        self.bicycleWheel.saveFile(self.bicycleWheel.FILE_PATH)
        self.assertEqual([100.0, 10.0, 12], self.bicycleWheel.loadFile(self.bicycleWheel.FILE_PATH))
    
    def test_get_default_minimum_wheel_size_allowance_with_default_hub_size_of_10(self):
        self.assertEqual(40, self.bicycleWheel.getMinWheelSizeAllowance())
        
    def test_get_minimum_wheel_size_allowance_when_setting_hub_to_15(self):
        self.bicycleWheel.setHubSize(15)
        self.assertEqual(60, self.bicycleWheel.getMinWheelSizeAllowance())
        
    def test_get_default_maximum_hub_size_allowance_with_default_wheel_size_of_80(self):
        self.assertEqual(20, self.bicycleWheel.getMaxHubSizeAllowance())
        
    def test_get_maximum_hub_size_when_setting_wheel_size_to_100(self):
        self.bicycleWheel.setWheelSize(100)
        self.assertEqual(25, self.bicycleWheel.getMaxHubSizeAllowance())