# -*- coding: utf-8 -*-

import init
import unittest
from unittest.mock import Mock
import block
import project
import node
from node.test import TestNode
import nodeIO
import sys
sys.path.append("../nyancode-runtime-std")

sys.path.append("../nyancode-runtime-std")


def testProjectNode():
    r = node.new("RootNode")
    blk = block.Block()
    n = node.new("MessageNode", parent_block=blk)
    n.setSingleParameter("title", "title")
    n.setSingleParameter("message", "message")
    blk.insert(n)
    r.setSingleChildBlock("block", blk)
    return r


def nestedProjectNode():
    r = node.new("RootNode")
    blk = block.Block()
    n = node.new("QuestionBranchNode", parent_block=blk)
    n.setSingleParameter("title", "title")
    n.setSingleParameter("message", "message")
    blk.insert(n)
    r.setSingleChildBlock("block", blk)
    n.setSingleChildBlock("yes", block.Block(parent_node=n))
    return r


class TestProjectManager(unittest.TestCase):
    def test_new(self):
        m = project.Manager()
        m.new("new project")
        # root nodeができている
        self.assertTrue(isinstance(m.root_node, node.RootNode))
        # root nodeの下に最初のブロックができてるか
        self.assertTrue(isinstance(
            m.root_node.child_blocks["block"], block.Block))
        # ビューで閲覧対象のブロックがルートノードのブロックになっているか
        self.assertEqual(m.root_node.child_blocks["block"], m.browsing_block)
        self.assertEqual("new project", m.project_name)  # プロジェクト名が設定されているか
        self.assertEqual("", m.project_path)  # 保存してないので、パスはまだ設定されてない
        self.assertFalse(m.has_changes)

    def test_getList(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        want = [
            ("メッセージを表示", 2, 0)
        ]
        self.assertEqual(want, m.getList())

    def test_insertNodeToCurrentBlock(self):
        n = testProjectNode()
        m = project.Manager()
        m.has_changes = False
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        n2 = node.new("MessageNode")
        n2.setSingleParameter("title", "title2")
        n2.setSingleParameter("message", "message2")
        m.insertNodeToCurrentBlock(n2)
        self.assertEqual(2, len(n.child_blocks["block"].nodes))
        want = [
            ("メッセージを表示", 2, 0),
            ("メッセージを表示", 2, 0)
        ]
        self.assertEqual(want, m.getList())
        self.assertTrue(m.has_changes)

    def test_deleteMultipleNodes(self):
        n = testProjectNode()
        m = project.Manager()
        m.has_changes = False
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.deleteMultipleNodes([0])
        self.assertEqual(0, len(n.child_blocks["block"].nodes))
        want = []
        self.assertTrue(m.has_changes)
        self.assertEqual(want, m.getList())

    def test_outputProgram(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        want = '\n'.join([
            '# generated by nyancode.',
            'import nyancode_runtime_std as nyancode',
            '',
            'nyancode.message("title", "message")'
        ])
        self.assertEqual(want, m.outputProgram())

    def test_outputProgramForDirectRun(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        # direct run だとimport分が消える
        want = '\n'.join([
            '# generated by nyancode.',
            '',
            'nyancode.message("title", "message")'
        ])
        self.assertEqual(want, m.outputProgramForDirectRun())

    def test_outputProject(self):
        n = testProjectNode()
        nodeIOMock = Mock()
        m = project.Manager(nodeIO=nodeIOMock)
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.outputProject()
        nodeIOMock.dump.assert_called()

    def test_GetProjectName(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.project_path = ""
        self.assertEqual("", m.getProjectName())
        m.project_path = "D:\\test\\project.pj"
        self.assertEqual("project", m.getProjectName())

    def test_mustSaveAs(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.project_path = ""
        self.assertTrue(m.mustSaveAs())
        m.project_path = "D:\\test\\project.pj"
        self.assertFalse(m.mustSaveAs())

    def test_saveAs(self):
        n = testProjectNode()
        projectIOMock = Mock()
        m = project.Manager(projectIO=projectIOMock)
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.has_changes = True
        m.saveAs("D:\\test\\project.ncp")
        self.assertEqual("D:\\test\\project.ncp", m.project_path)
        self.assertFalse(m.has_changes)
        projectIOMock.dump.assert_called()

    def test_save(self):
        n = testProjectNode()
        projectIOMock = Mock()
        m = project.Manager(projectIO=projectIOMock)
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.has_changes = True
        m.project_path = "D:\\test\\project.ncp"
        m.save()
        self.assertFalse(m.has_changes)
        projectIOMock.dump.assert_called()

    def test_savePythonProgram(self):
        n = testProjectNode()
        projectIOMock = Mock()
        m = project.Manager(projectIO=projectIOMock)
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.savePythonProgram("D:\\test\\project.py")
        projectIOMock.dump.assert_called()

    def test_load(self):
        n = testProjectNode()
        nodeIOMock = Mock()
        nodeIOMock.load = Mock(return_value=n)
        projectIOMock = Mock()
        projectIOMock.load = Mock(return_value=nodeIO.NodeIO().dump(n))
        m = project.Manager(nodeIO=nodeIOMock, projectIO=projectIOMock)
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.load("D:\\test\\project.ncp")
        projectIOMock.load.assert_called()
        nodeIOMock.load.assert_called()
        self.assertEqual(n, m.root_node)
        self.assertEqual("D:\\test\\project.ncp", m.project_path)
        self.assertEqual(n.child_blocks["block"], m.browsing_block)

    def test_browseRootNodeContent(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browseRootNodeContent()
        self.assertEqual(n.child_blocks["block"], m.browsing_block)

# skip test for run

    def test_getNodeAt(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        got = m.getNodeAt(0)
        self.assertEqual(n.child_blocks["block"].nodes[0], got)

    def test_enterSubBlock(self):
        n = nestedProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.enterSubBlock(0, "yes")
        self.assertEqual(2, m.scope_level)
        self.assertEqual(
            n.child_blocks["block"].nodes[0].child_blocks["yes"],
            m.browsing_block)

    def test_leaveSubBlock(self):
        n = nestedProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        m.enterSubBlock(0, "yes")
        ret = m.leaveSubBlock()
        self.assertEqual(1, m.scope_level)
        self.assertEqual(n.child_blocks["block"], m.browsing_block)
        self.assertEqual(0, ret)  # 正しいカーソル位置が返ってきてほしい

    def test_leaveSubBlock_atRoot(self):
        n = nestedProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        ret = m.leaveSubBlock()
        self.assertEqual(1, m.scope_level)
        self.assertEqual(None, ret)

    def test_generateNode(self):
        n = testProjectNode()
        m = project.Manager()
        m.root_node = n
        m.browsing_block = n.child_blocks["block"]
        nd = m.generateNode("TestNode")
        self.assertTrue(isinstance(nd, TestNode))
        self.assertEqual(m.browsing_block, nd.parent_block)
