from big_ol_pile_of_manim_imports import *
from functools import reduce

class OpeningQuote(Scene):
    def construct(self):
        words = TextMobject([
            "Lisa:",
            "Well, where's my dad?\\\\ \\\\",
            "Frink:",
            """Well, it should be obvious to even the most 
            dimwitted individual who holds an advanced degree 
            in hyperbolic topology that Homer Simpson has stumbled
            into...(dramatic pause)...""",
            "the third dimension."
        ])
        words.set_width(FRAME_WIDTH - 2)
        words.to_edge(UP)
        words.split()[0].set_color(YELLOW)
        words.split()[2].set_color(YELLOW)

        three_d = words.submobjects.pop()
        three_d.set_color(BLUE)
        self.play(FadeIn(words))
        self.play(Write(three_d))
        self.wait(2)

class QuickFootnote(TeacherStudentsScene):
    def construct(self):
        self.setup()
        self.teacher_says("Quick footnote here...")
        self.random_blink()
        self.play(
            random.choice(self.get_students()).change_mode, "happy"
        )
        self.random_blink()

class PeakOutsideFlatland(TeacherStudentsScene):
    def construct(self):
        self.setup()
        self.teacher_says("Peak outside flatland")
        self.wait()
        student = self.get_students()[0]
        self.student_thinks(student_index = 0)
        student.bubble.make_green_screen()
        self.wait()

class SymbolicThreeDTransform(Scene):
    CONFIG = {
        "input_coords" : [2, 6, -1],
        "output_coords" : [3, 2, 0],
        "title" : "Three-dimensional transformation",
    }
    def construct(self):
        in_vect = Matrix(self.input_coords)
        out_vect = Matrix(self.output_coords)
        in_vect.set_color(BLUE)
        out_vect.set_color(GREEN)
        func = TexMobject("L(\\vec{\\textbf{v}})")
        point = VectorizedPoint(func.get_center())
        in_vect.next_to(func, LEFT, buff = 1)
        out_vect.next_to(func, RIGHT, buff = 1)
        in_words = TextMobject("Input")
        in_words.next_to(in_vect, DOWN)
        in_words.set_color(BLUE_C)
        out_words = TextMobject("Output")
        out_words.next_to(out_vect, DOWN)
        out_words.set_color(GREEN_C)


        title = TextMobject(self.title)
        title.to_edge(UP)
        self.add(title)

        self.play(Write(func))
        self.play(Write(in_vect), Write(in_words))
        self.wait()
        self.add(in_vect.copy())
        self.play(Transform(in_vect, point, lag_ratio = 0.5))
        self.play(Transform(in_vect, out_vect, lag_ratio = 0.5))
        self.add(out_words)
        self.wait()

class ThreeDLinearTransformExample(Scene):
    pass

class SingleVectorToOutput(Scene):
    pass

class InputWordOutputWord(Scene):
    def construct(self):
        self.add(TextMobject("Input").scale(2))
        self.wait()
        self.clear()
        self.add(TextMobject("Output").scale(2))
        self.wait()

class TransformOnlyBasisVectors(Scene):
    pass

class IHatJHatKHatWritten(Scene):
    def construct(self):
        for char, color in zip(["\\imath", "\\jmath", "k"], [X_COLOR, Y_COLOR, Z_COLOR]):
            sym = TexMobject("{\\hat{%s}}"%char)
            sym.scale(3)
            sym.set_color(color)
            self.play(Write(sym))
            self.wait()
            self.clear()
 
class PutTogether3x3Matrix(Scene):
    CONFIG = {
        "col1" : [1, 0, -1],
        "col2" : [1, 1, 0],
        "col3" : [1, 0, 1],
    }
    def construct(self):
        i_to = TexMobject("\\hat{\\imath} \\to").set_color(X_COLOR)
        j_to = TexMobject("\\hat{\\jmath} \\to").set_color(Y_COLOR)
        k_to = TexMobject("\\hat{k} \\to").set_color(Z_COLOR)
        i_array = Matrix(self.col1)
        j_array = Matrix(self.col2)
        k_array = Matrix(self.col3)
        everything = VMobject(
            i_to, i_array, TexMobject("=").set_color(BLACK),
            j_to, j_array, TexMobject("=").set_color(BLACK),
            k_to, k_array, TexMobject("=").set_color(BLACK),
        )
        everything.arrange(RIGHT, buff = 0.1)
        everything.set_width(FRAME_WIDTH-1)
        everything.to_edge(DOWN)

        i_array.set_color(X_COLOR)
        j_array.set_color(Y_COLOR)
        k_array.set_color(Z_COLOR)
        arrays = [i_array, j_array, k_array]
        matrix = Matrix(reduce(
            lambda a1, a2 : np.append(a1, a2, axis = 1),
            [m.copy().get_mob_matrix() for m in arrays]
        ))
        matrix.to_edge(DOWN)

        start_entries = reduce(op.add, [a.get_entries().split() for a in arrays])
        target_entries = matrix.get_mob_matrix().transpose().flatten()
        start_l_bracket = i_array.get_brackets().split()[0]
        start_r_bracket = k_array.get_brackets().split()[1]
        start_brackets = VMobject(start_l_bracket, start_r_bracket)
        target_bracketes = matrix.get_brackets()

        for mob in everything.split():
            self.play(Write(mob, run_time = 1))
        self.wait()
        self.play(
            FadeOut(everything),
            Transform(VMobject(*start_entries), VMobject(*target_entries)),
            Transform(start_brackets, target_bracketes)
        )
        self.wait()

class RotateSpaceAboutYAxis(Scene):
    pass

class RotateOnlyBasisVectorsAboutYAxis(Scene):
    pass

class PutTogetherRotationMatrix(PutTogether3x3Matrix):
    CONFIG = {
        "col1" : [0, 0, -1],
        "col2" : [0, 1, 0],
        "col3" : [1, 0, 0]
    }

class ScaleAndAddBeforeTransformation(Scene):
    pass

class ShowVCoordinateMeaning(Scene):
    CONFIG = {
        "v_str" : "\\vec{\\textbf{v}}",
        "i_str" : "\\hat{\\imath}",
        "j_str" : "\\hat{\\jmath}",
        "k_str" : "\\hat{k}",
        "post_transform" : False,
    }
    def construct(self):
        v = TexMobject(self.v_str)
        v.set_color(YELLOW)
        eq = TexMobject("=")
        coords = Matrix(["x", "y", "z"])
        eq2 = eq.copy()
        if self.post_transform:
            L, l_paren, r_paren = list(map(TexMobject, "L()"))
            parens = VMobject(l_paren, r_paren)
            parens.scale(2)
            parens.stretch_to_fit_height(
                coords.get_height()
            )
            VMobject(L, l_paren, coords, r_paren).arrange(buff = 0.1)
            coords.submobjects = [L, l_paren] + coords.submobjects + [r_paren]

        lin_comb = VMobject(*list(map(TexMobject, [
            "x", self.i_str, "+",
            "y", self.j_str, "+",
            "z", self.k_str,
        ])))
        lin_comb.arrange(
            RIGHT, buff = 0.1, 
            aligned_edge = ORIGIN if self.post_transform else DOWN
        )
        lin_comb_parts = np.array(lin_comb.split())
        new_x, new_y, new_z = lin_comb_parts[[0, 3, 6]]
        i, j, k = lin_comb_parts[[1, 4, 7]]
        plusses = lin_comb_parts[[2, 5]]
        i.set_color(X_COLOR)
        j.set_color(Y_COLOR)
        k.set_color(Z_COLOR)

        everything = VMobject(v, eq, coords, eq2, lin_comb)
        everything.arrange(buff = 0.2)
        everything.set_width(FRAME_WIDTH - 1)
        everything.to_edge(DOWN)
        if not self.post_transform:
            lin_comb.shift(0.35*UP)

        self.play(*list(map(Write, [v, eq, coords])))
        self.wait()
        self.play(
            Transform(
                coords.get_entries().copy(),
                VMobject(new_x, new_y, new_z),
                path_arc = -np.pi,
                lag_ratio = 0.5
            ),
            Write(VMobject(*[eq2, i, j, k] + list(plusses))),
            run_time = 3
        )
        self.wait()

class ScaleAndAddAfterTransformation(Scene):
    pass

class ShowVCoordinateMeaningAfterTransform(ShowVCoordinateMeaning):
    CONFIG = {
        "v_str" : "L(\\vec{\\textbf{v}})",
        "i_str" : "L(\\hat{\\imath})",
        "j_str" : "L(\\hat{\\jmath})",
        "k_str" : "L(\\hat{k})",
        "post_transform" : True,
    }

class ShowMatrixVectorMultiplication(Scene):
    def construct(self):
        matrix = Matrix(np.arange(9).reshape((3, 3)))
        vect = Matrix(list("xyz"))
        vect.set_height(matrix.get_height())
        col1, col2, col3 = columns = [
            Matrix(col)
            for col in matrix.copy().get_mob_matrix().transpose()
        ]
        coords = x, y, z = [m.copy() for m in vect.get_entries().split()]
        eq, plus1, plus2 = list(map(TexMobject, list("=++")))
        everything = VMobject(
            matrix, vect, eq,
            x, col1, plus1,
            y, col2, plus2,
            z, col3
        )
        everything.arrange(buff = 0.1)
        everything.set_width(FRAME_WIDTH-1)
        result = VMobject(x, col1, plus1, y, col2, plus2, z, col3)

        trips = [
            (matrix, DOWN, "Transformation"),
            (vect, UP, "Input vector"),
            (result, DOWN, "Output vector"),
        ]
        braces = []
        for mob, direction, text in trips:
            brace = Brace(mob, direction)
            words = TextMobject(text)
            words.next_to(brace, direction)
            brace.add(words)
            braces.append(brace)
        matrix_brace, vect_brace, result_brace = braces


        self.play(*list(map(Write, [matrix, vect])), run_time = 2)
        self.play(Write(matrix_brace, run_time = 1))
        self.play(Write(vect_brace, run_time = 1))
        sexts = list(zip(
            matrix.get_mob_matrix().transpose(),
            columns,
            vect.get_entries().split(),
            coords,
            [eq, plus1, plus2],
            [X_COLOR, Y_COLOR, Z_COLOR]
        ))
        for o_col, col, start_coord, coord, sym, color in sexts:
            o_col = VMobject(*o_col)
            self.play(
                start_coord.set_color, YELLOW,
                o_col.set_color, color
            )
            coord.set_color(YELLOW)
            col.set_color(color)
            self.play(
                Write(col.get_brackets()),
                Transform(
                    o_col.copy(), col.get_entries(),
                    path_arc = -np.pi
                ),
                Transform(
                    start_coord.copy(), coord, 
                    path_arc = -np.pi
                ),
                Write(sym)
            )
            self.wait()
        self.play(Write(result_brace, run_time = 1))
        self.wait()

class ShowMatrixMultiplication(Scene):
    def construct(self):
        right = Matrix(np.arange(9).reshape((3, 3)))
        left = Matrix(np.random.random_integers(-5, 5, (3, 3)))
        VMobject(left, right).arrange(buff = 0.1)
        right.set_column_colors(X_COLOR, Y_COLOR, Z_COLOR)
        left.set_color(PINK)

        trips = [
            (right, DOWN, "First transformation"),
            (left, UP, "Second transformation"),
        ]
        braces = []
        for mob, direction, text in trips:
            brace = Brace(mob, direction)
            words = TextMobject(text)
            words.next_to(brace, direction)
            brace.add(words)
            braces.append(brace)
        right_brace, left_brace = braces

        VMobject(*self.get_mobjects()).set_width(FRAME_WIDTH-1)

        self.add(right, left)
        self.play(Write(right_brace))
        self.play(Write(left_brace))
        self.wait()

class ApplyTwoSuccessiveTransforms(Scene):
    pass

class ComputerGraphicsAndRobotics(Scene):
    def construct(self):
        mob = VMobject(
            TextMobject("Computer graphics"),
            TextMobject("Robotics")
        )
        mob.arrange(DOWN, buff = 1)
        self.play(Write(mob, run_time = 1))
        self.wait()

class ThreeDRotation(Scene):
    pass

class ThreeDRotationBrokenUp(Scene):
    pass

class SymbolicTwoDToThreeDTransform(SymbolicThreeDTransform):
    CONFIG = {
        "input_coords" : [2, 6],
        "output_coords" : [3, 2, 0],
        "title" : "Two dimensions to three dimensions",
    }

class SymbolicThreeDToTwoDTransform(SymbolicThreeDTransform):
    CONFIG = {
        "input_coords" : [4, -3, 1],
        "output_coords" : [8, 4],
        "title" : "Three dimensions to two dimensions",
    }

class QuestionsToPonder(Scene):
    def construct(self):
        title = TextMobject("Questions to ponder")
        title.set_color(YELLOW).to_edge(UP)
        self.add(title)
        questions = VMobject(*list(map(TextMobject, [
            "1. Can you visualize these transformations?",
            "2. Can you represent them with matrices?",
            "3. How many rows and columns?",
            "4. When can you multiply these matrices?",
        ])))
        questions.arrange(DOWN, buff = 1, aligned_edge = LEFT)
        questions.to_edge(LEFT)
        for question in questions.split():
            self.play(Write(question, run_time = 1))
            self.wait()

class NextVideo(Scene):
    def construct(self):
        title = TextMobject("""
            Next video: The determinant
        """)
        title.set_width(FRAME_WIDTH - 2)
        title.to_edge(UP)
        rect = Rectangle(width = 16, height = 9, color = BLUE)
        rect.set_height(6)
        rect.next_to(title, DOWN)

        self.add(title)
        self.play(ShowCreation(rect))
        self.wait()  


















