func main() {
	flag.Usage = usage
	flag.Parse()

	if *help {
		usage()
	}

	// Read the configuration
	c, err := config.ReadConfigFromFile(cfgfile, source)
	HandleError(err)

	// Add the missing sourcePath
	c.SourcePath = *source

	// Create a Process
	process := &Process{Done: make(chan bool),
		Source:         *source,
		Started:        true,
		PagesFileInfo:  make(map[string]*os.FileInfo),
		AssetsFileInfo: make(map[string]*os.FileInfo),
	}

	// Create a plugin configuration object
	configPlugin := &gutenberg.PluginConfig{SourcePath: *source,
		OutputDirectory: c.OutputDirectory}
	// Get the custom HTML transformer
	process.CustomTransformer = gutenberg.NewCustomHtml(c)
	// Add new Custom Plugins to the transformer
	process.CustomTransformer.AddPlugin("dot", plugins.NewDotPlugin(configPlugin))
	process.CustomTransformer.AddPlugin("note", plugins.NewNotePlugin())

	// Create output directory if it does not exist
	err = os.Mkdir(c.OutputDirectory, 0755)

	// Rebuild the entire book
	if *rebuild {
		GenerateWholeBook(process)
	} else {
		HandleError(ReadAllModTimes(c, process))
	}

	// Go into watch mode
	if *watchMode {
		WatchMode(*interval, process)
	}
}
func WatchMode(delay int64, p *Process) {
	go func() {
		for true {
			// Get the parts of the config file
			sourcePath := config.SourcePath(source)
			configFileLocation := config.ConfigFile(sourcePath, cfgfile)

			// Set the config file name
			configFileInfo, err := os.Stat(configFileLocation)
			if err != nil {
				log.Printf("Failed to read configuration file from %s\n", configFileLocation)
				continue
			}

			// Read the configuration
			c, err := config.ReadConfigFromFile(cfgfile, source)
			if err != nil {
				log.Printf("Failed to read configuration file from %s\n", configFileLocation)
				continue
			}

			// Point to the actual instance
			configFileInfoInstance := *p.ConfigFileInfo

			// If config time finished
			if !configFileInfo.ModTime().Equal(configFileInfoInstance.ModTime()) {
				log.Printf("Configuration file changed, regenerating whole book\n")
				// Re-generate the whole book
				GenerateWholeBook(p)
				// Save the new configuration file info
				p.ConfigFileInfo = &configFileInfo
				// Done, let's watch again
				continue
			}

			// Read all the layouts for html
			htmlLayouts := c.Layouts["html"]
			indexLayout := htmlLayouts.Index
			pageLayout := htmlLayouts.Page

			// Get the file info for the pageLayout file
			pageLayoutFile := fmt.Sprintf("%s/%s", p.Source, pageLayout)
			pageLayoutFileInfo, err := os.Stat(pageLayoutFile)
			if err != nil {
				log.Printf("Index layout file changed, regenerating whole book\n")
				// Re-generate the whole book
				GenerateWholeBook(p)
				// Update the time
				p.PageLayoutFileInfo = &pageLayoutFileInfo
				continue
			}

			// Get the file info for the pageLayout file
			indexLayoutFile := fmt.Sprintf("%s/%s", p.Source, indexLayout)
			indexLayoutFileInfo, err := os.Stat(indexLayoutFile)
			if err != nil {
				log.Printf("Index layout file changed, regenerating whole book\n")
				// Re-generate the whole book
				GenerateWholeBook(p)
				// Update the time
				p.IndexFileInfo = &indexLayoutFileInfo
				continue
			}

			// Read the page layout file in
			layoutBytes, err := ioutil.ReadFile(pageLayoutFile)
			if err != nil {
				log.Printf("no layout file found for %s\n", pageLayoutFile)
			}

			// Parse the template into an object
			pageTemplate, err := template.New("pageTemplate").Parse(string(layoutBytes))
			if err != nil {
				log.Printf("invalid template found in %s page template file\n", pageLayoutFile)
			}

			// Copy over all the assets
			for _, asset := range c.Assets {
				assetLocation := fmt.Sprintf("%s/%s", p.Source, asset)
				fileContent, err := ioutil.ReadFile(assetLocation)

				// Get the file info for the pageLayout file
				assetFileInfo, err := os.Stat(assetLocation)
				if err == nil {
					modTime := *p.AssetsFileInfo[asset]

					if modTime != nil && modTime.ModTime().Equal(assetFileInfo.ModTime()) {
						continue
					}

					p.AssetsFileInfo[asset] = &assetFileInfo
				}

				if err == nil {
					assetOutputLocation := fmt.Sprintf("%s/%s", c.OutputDirectory, filepath.Base(asset))
					log.Printf("Saving asset to %s\n", assetOutputLocation)

					err = ioutil.WriteFile(assetOutputLocation, fileContent, 0755)
					if err != nil {
						log.Fatalf("Failed to save the asset %s to %s\n", asset, assetOutputLocation)
					}
				} else {
					log.Fatalf("Could not locate the asset %s\n", asset)
				}
			}

			// We only re-generate pages that have changed
			// Read all the pages in
			for _, page := range c.TableOfContents {
				// Split the file up so we can get the "name"
				fileNameParts := strings.Split(page.File, ".")
				fileName := strings.Join(fileNameParts[0:(len(fileNameParts)-1)], ".")

				// Read the page
				pageFile := fmt.Sprintf("%s/%s", p.Source, page.File)

				// Get the file info for the pageLayout file
				pageFileInfo, err := os.Stat(pageFile)
				if err == nil {
					modTime := *p.PagesFileInfo[page.File]

					if modTime != nil && modTime.ModTime().Equal(pageFileInfo.ModTime()) {
						continue
					}

					log.Printf("Generate page %s\n", page.File)
					p.PagesFileInfo[page.File] = &pageFileInfo
				}

				// Read the page into memory
				data, err := ioutil.ReadFile(pageFile)
				if err != nil {
					continue
				}

				// Get the custom Html transformer
				customTransformer := gutenberg.NewCustomHtml(c)

				// Render the mardown
				html := customTransformer.Transform(data)

				// Pass to the template if it's defined
				if pageTemplate != nil {
					// var buffer bytes.Buffer
					buffer := bytes.NewBuffer(nil)
					err = pageTemplate.Execute(buffer, BuildContext(string(html), c))
					if err != nil {
						log.Fatalf("Failed to execute template %s\n", pageLayoutFile)
						os.Exit(0)
					}

					// Save the data as the new page
					html = buffer.Bytes()
				}

				// Let's write the resulting page out
				err = ioutil.WriteFile(fmt.Sprintf("%s/%s.html", c.OutputDirectory, fileName), html, 0755)
				if err != nil {
					continue
				}
			}

			// Just sleep a bit and watch again
			time.Sleep(time.Duration(delay) * time.Millisecond)
		}
	}()

	// Wait until we are done
	<-p.Done
}
func GenerateBook(p *Process, c *config.Config) error {
	// Read all the layouts for html
	htmlLayouts := c.Layouts["html"]
	indexLayout := htmlLayouts.Index
	pageLayout := htmlLayouts.Page

	// Get the parts of the config file
	sourcePath := config.SourcePath(source)
	// Set the config file name
	configFile := config.ConfigFile(sourcePath, cfgfile)
	configFileInfo, err := os.Stat(configFile)
	if err == nil {
		p.ConfigFileInfo = &configFileInfo
	}

	// Get the right location for the page layout file
	indexLayoutFile := fmt.Sprintf("%s/%s", p.Source, indexLayout)
	// Get the file info for the pageLayout file
	indexLayoutFileInfo, err := os.Stat(indexLayoutFile)
	if err == nil {
		p.IndexFileInfo = &indexLayoutFileInfo
	}

	// Get the right location for the page layout file
	pageLayoutFile := fmt.Sprintf("%s/%s", p.Source, pageLayout)
	// Get the file info for the pageLayout file
	pageLayoutFileInfo, err := os.Stat(pageLayoutFile)
	if err == nil {
		p.PageLayoutFileInfo = &pageLayoutFileInfo
	}

	// Read the page layout file in
	layoutBytes, err := ioutil.ReadFile(pageLayoutFile)
	if err != nil {
		log.Printf("no layout file found for %s\n", pageLayoutFile)
	}

	// Parse the template into an object
	pageTemplate, err := template.New("pageTemplate").Parse(string(layoutBytes))
	if err != nil {
		log.Printf("invalid template found in %s page template file\n", pageLayoutFile)
	}

	// Copy over all the assets
	for _, asset := range c.Assets {
		assetLocation := fmt.Sprintf("%s/%s", p.Source, asset)
		fileContent, err := ioutil.ReadFile(assetLocation)

		// Get the file info for the pageLayout file
		assetFileInfo, err := os.Stat(assetLocation)
		if err == nil {
			p.AssetsFileInfo[asset] = &assetFileInfo
		}

		if err == nil {
			assetOutputLocation := fmt.Sprintf("%s/%s", c.OutputDirectory, filepath.Base(asset))
			log.Printf("Saving asset to %s\n", assetOutputLocation)

			err = ioutil.WriteFile(assetOutputLocation, fileContent, 0755)
			if err != nil {
				log.Fatalf("Failed to save the asset %s to %s\n", asset, assetOutputLocation)
			}
		} else {
			log.Fatalf("Could not locate the asset %s\n", asset)
		}
	}

	// Read all the pages in
	for _, page := range c.TableOfContents {
		log.Printf("Generate page %s\n", page.File)

		// Split the file up so we can get the "name"
		fileNameParts := strings.Split(page.File, ".")
		fileName := strings.Join(fileNameParts[0:(len(fileNameParts)-1)], ".")

		// Read the page
		pageFile := fmt.Sprintf("%s/%s", p.Source, page.File)

		// Get the file info for the pageLayout file
		pageFileInfo, err := os.Stat(pageFile)
		if err != nil {
			return err
		}

		if err == nil {
			p.PagesFileInfo[page.File] = &pageFileInfo
		}

		// Read the page into memory
		data, err := ioutil.ReadFile(pageFile)
		if err != nil {
			return err
		}

		// Get the custom Html transformer
		customTransformer := gutenberg.NewCustomHtml(c)

		// Render the mardown
		html := customTransformer.Transform(data)

		// Pass to the template if it's defined
		if pageTemplate != nil {
			// var buffer bytes.Buffer
			buffer := bytes.NewBuffer(nil)
			err = pageTemplate.Execute(buffer, BuildContext(string(html), c))
			if err != nil {
				log.Fatalf("Failed to execute template %s\n", pageLayoutFile)
				os.Exit(0)
			}

			// Save the data as the new page
			html = buffer.Bytes()
		}

		// Let's write the resulting page out
		err = ioutil.WriteFile(fmt.Sprintf("%s/%s.html", c.OutputDirectory, fileName), html, 0755)
		if err != nil {
			return err
		}
	}

	return nil
}